summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruno Thomsen <bruno.thomsen@gmail.com>2019-08-22 09:19:35 -0400
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2019-08-27 12:24:15 -0400
commit0e735eaae1650a2e26835cc776f496e06a87be9f (patch)
treed077e7192c7f1cbbdaafe3616875f31a2b273293
parent7f43020e3bdb63d65661ed377682702f8b34d3ea (diff)
rtc: pcf2127: add watchdog feature support
Add partial support for the watchdog functionality of both PCF2127 and PCF2129 chips. The programmable watchdog timer is currently using a fixed clock source of 1Hz. This result in a selectable range of 1-255 seconds, which covers most embedded Linux use-cases. Clock sources of 4096Hz, 64Hz and 1/60Hz is mostly useful in MCU use-cases. Countdown timer not available when using watchdog feature. Signed-off-by: Bruno Thomsen <bruno.thomsen@gmail.com> Acked-by: Guenter Roeck <linux@roeck-us.net> Link: https://lore.kernel.org/r/20190822131936.18772-4-bruno.thomsen@gmail.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
-rw-r--r--drivers/rtc/Kconfig7
-rw-r--r--drivers/rtc/rtc-pcf2127.c118
2 files changed, 124 insertions, 1 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 63bd72a96210..758f7a417470 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -888,7 +888,12 @@ config RTC_DRV_PCF2127
888 depends on RTC_I2C_AND_SPI 888 depends on RTC_I2C_AND_SPI
889 help 889 help
890 If you say yes here you get support for the NXP PCF2127/29 RTC 890 If you say yes here you get support for the NXP PCF2127/29 RTC
891 chips. 891 chips with integrated quartz crystal for industrial applications.
892 Both chips also have watchdog timer and tamper switch detection
893 features.
894
895 PCF2127 has an additional feature of 512 bytes battery backed
896 memory that's accessible using nvmem interface.
892 897
893 This driver can also be built as a module. If so, the module 898 This driver can also be built as a module. If so, the module
894 will be called rtc-pcf2127. 899 will be called rtc-pcf2127.
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index ee4921e4a47c..8d6eda455d81 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -5,6 +5,9 @@
5 * 5 *
6 * Author: Renaud Cerrato <r.cerrato@til-technologies.fr> 6 * Author: Renaud Cerrato <r.cerrato@til-technologies.fr>
7 * 7 *
8 * Watchdog and tamper functions
9 * Author: Bruno Thomsen <bruno.thomsen@gmail.com>
10 *
8 * based on the other drivers in this same directory. 11 * based on the other drivers in this same directory.
9 * 12 *
10 * Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf 13 * Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf
@@ -18,6 +21,7 @@
18#include <linux/module.h> 21#include <linux/module.h>
19#include <linux/of.h> 22#include <linux/of.h>
20#include <linux/regmap.h> 23#include <linux/regmap.h>
24#include <linux/watchdog.h>
21 25
22/* Control register 1 */ 26/* Control register 1 */
23#define PCF2127_REG_CTRL1 0x00 27#define PCF2127_REG_CTRL1 0x00
@@ -35,6 +39,13 @@
35#define PCF2127_REG_DW 0x07 39#define PCF2127_REG_DW 0x07
36#define PCF2127_REG_MO 0x08 40#define PCF2127_REG_MO 0x08
37#define PCF2127_REG_YR 0x09 41#define PCF2127_REG_YR 0x09
42/* Watchdog registers */
43#define PCF2127_REG_WD_CTL 0x10
44#define PCF2127_BIT_WD_CTL_TF0 BIT(0)
45#define PCF2127_BIT_WD_CTL_TF1 BIT(1)
46#define PCF2127_BIT_WD_CTL_CD0 BIT(6)
47#define PCF2127_BIT_WD_CTL_CD1 BIT(7)
48#define PCF2127_REG_WD_VAL 0x11
38/* 49/*
39 * RAM registers 50 * RAM registers
40 * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is 51 * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is
@@ -45,9 +56,15 @@
45#define PCF2127_REG_RAM_WRT_CMD 0x1C 56#define PCF2127_REG_RAM_WRT_CMD 0x1C
46#define PCF2127_REG_RAM_RD_CMD 0x1D 57#define PCF2127_REG_RAM_RD_CMD 0x1D
47 58
59/* Watchdog timer value constants */
60#define PCF2127_WD_VAL_STOP 0
61#define PCF2127_WD_VAL_MIN 2
62#define PCF2127_WD_VAL_MAX 255
63#define PCF2127_WD_VAL_DEFAULT 60
48 64
49struct pcf2127 { 65struct pcf2127 {
50 struct rtc_device *rtc; 66 struct rtc_device *rtc;
67 struct watchdog_device wdd;
51 struct regmap *regmap; 68 struct regmap *regmap;
52}; 69};
53 70
@@ -220,6 +237,74 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset,
220 return ret ?: bytes; 237 return ret ?: bytes;
221} 238}
222 239
240/* watchdog driver */
241
242static int pcf2127_wdt_ping(struct watchdog_device *wdd)
243{
244 struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd);
245
246 return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, wdd->timeout);
247}
248
249/*
250 * Restart watchdog timer if feature is active.
251 *
252 * Note: Reading CTRL2 register causes watchdog to stop which is unfortunate,
253 * since register also contain control/status flags for other features.
254 * Always call this function after reading CTRL2 register.
255 */
256static int pcf2127_wdt_active_ping(struct watchdog_device *wdd)
257{
258 int ret = 0;
259
260 if (watchdog_active(wdd)) {
261 ret = pcf2127_wdt_ping(wdd);
262 if (ret)
263 dev_err(wdd->parent,
264 "%s: watchdog restart failed, ret=%d\n",
265 __func__, ret);
266 }
267
268 return ret;
269}
270
271static int pcf2127_wdt_start(struct watchdog_device *wdd)
272{
273 return pcf2127_wdt_ping(wdd);
274}
275
276static int pcf2127_wdt_stop(struct watchdog_device *wdd)
277{
278 struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd);
279
280 return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL,
281 PCF2127_WD_VAL_STOP);
282}
283
284static int pcf2127_wdt_set_timeout(struct watchdog_device *wdd,
285 unsigned int new_timeout)
286{
287 dev_dbg(wdd->parent, "new watchdog timeout: %is (old: %is)\n",
288 new_timeout, wdd->timeout);
289
290 wdd->timeout = new_timeout;
291
292 return pcf2127_wdt_active_ping(wdd);
293}
294
295static const struct watchdog_info pcf2127_wdt_info = {
296 .identity = "NXP PCF2127/PCF2129 Watchdog",
297 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
298};
299
300static const struct watchdog_ops pcf2127_watchdog_ops = {
301 .owner = THIS_MODULE,
302 .start = pcf2127_wdt_start,
303 .stop = pcf2127_wdt_stop,
304 .ping = pcf2127_wdt_ping,
305 .set_timeout = pcf2127_wdt_set_timeout,
306};
307
223static int pcf2127_probe(struct device *dev, struct regmap *regmap, 308static int pcf2127_probe(struct device *dev, struct regmap *regmap,
224 const char *name, bool has_nvmem) 309 const char *name, bool has_nvmem)
225{ 310{
@@ -242,6 +327,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
242 327
243 pcf2127->rtc->ops = &pcf2127_rtc_ops; 328 pcf2127->rtc->ops = &pcf2127_rtc_ops;
244 329
330 pcf2127->wdd.parent = dev;
331 pcf2127->wdd.info = &pcf2127_wdt_info;
332 pcf2127->wdd.ops = &pcf2127_watchdog_ops;
333 pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN;
334 pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX;
335 pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT;
336 pcf2127->wdd.min_hw_heartbeat_ms = 500;
337
338 watchdog_set_drvdata(&pcf2127->wdd, pcf2127);
339
245 if (has_nvmem) { 340 if (has_nvmem) {
246 struct nvmem_config nvmem_cfg = { 341 struct nvmem_config nvmem_cfg = {
247 .priv = pcf2127, 342 .priv = pcf2127,
@@ -253,6 +348,29 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
253 ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); 348 ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg);
254 } 349 }
255 350
351 /*
352 * Watchdog timer enabled and reset pin /RST activated when timed out.
353 * Select 1Hz clock source for watchdog timer.
354 * Timer is not started until WD_VAL is loaded with a valid value.
355 * Note: Countdown timer disabled and not available.
356 */
357 ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL,
358 PCF2127_BIT_WD_CTL_CD1 |
359 PCF2127_BIT_WD_CTL_CD0 |
360 PCF2127_BIT_WD_CTL_TF1 |
361 PCF2127_BIT_WD_CTL_TF0,
362 PCF2127_BIT_WD_CTL_CD1 |
363 PCF2127_BIT_WD_CTL_CD0 |
364 PCF2127_BIT_WD_CTL_TF1);
365 if (ret) {
366 dev_err(dev, "%s: watchdog config (wd_ctl) failed\n", __func__);
367 return ret;
368 }
369
370 ret = devm_watchdog_register_device(dev, &pcf2127->wdd);
371 if (ret)
372 return ret;
373
256 return rtc_register_device(pcf2127->rtc); 374 return rtc_register_device(pcf2127->rtc);
257} 375}
258 376