linux-watchdog.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Guenter Roeck <linux@roeck-us.net>
To: Chris Packham <chris.packham@alliedtelesis.co.nz>,
	a.zummo@towertech.it, alexandre.belloni@bootlin.com,
	wim@linux-watchdog.org
Cc: linux-rtc@vger.kernel.org, linux-watchdog@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2] rtc: ds1307: add support for watchdog timer on ds1388
Date: Fri, 27 Mar 2020 14:12:18 -0700	[thread overview]
Message-ID: <4aecb77e-f635-9bfd-c2bd-21cb68fa333d@roeck-us.net> (raw)
In-Reply-To: <20200327041809.2029-1-chris.packham@alliedtelesis.co.nz>

On 3/26/20 9:18 PM, Chris Packham wrote:
> The DS1388 variant has watchdog timer capabilities. When using a DS1388
> and having enabled CONFIG_WATCHDOG_CORE register a watchdog device for
> the DS1388.
> 
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
> ---
> This is going to the linux-watchdog list as well this time so it's probably the
> first time the watchdog maintainers have seen it.
> 
> Changes in v2:
> - Address review comments from Alexandre, the only functional change is setting
>   the hundredths of seconds to 0 instead of 99.
> 
>  drivers/rtc/rtc-ds1307.c | 97 ++++++++++++++++++++++++++++++++++++++++

	"select WATCHDOG_CORE if WATCHDOG"

should be added to Kconfig. While it makes sense for watchdog functionality
to depend on WATCHDOG, it should not depend on the existence of another
watchdog driver in the system.

>  1 file changed, 97 insertions(+)
> 
> diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
> index 31a38d468378..1452982c3a6a 100644
> --- a/drivers/rtc/rtc-ds1307.c
> +++ b/drivers/rtc/rtc-ds1307.c
> @@ -22,6 +22,7 @@
>  #include <linux/hwmon-sysfs.h>
>  #include <linux/clk-provider.h>
>  #include <linux/regmap.h>
> +#include <linux/watchdog.h>
>  
>  /*
>   * We can't determine type by probing, but if we expect pre-Linux code
> @@ -144,8 +145,15 @@ enum ds_type {
>  #	define M41TXX_BIT_CALIB_SIGN	BIT(5)
>  #	define M41TXX_M_CALIBRATION	GENMASK(4, 0)
>  
> +#define DS1388_REG_WDOG_HUN_SECS	0x08
> +#define DS1388_REG_WDOG_SECS		0x09
>  #define DS1388_REG_FLAG			0x0b
> +#	define DS1388_BIT_WF		BIT(6)
>  #	define DS1388_BIT_OSF		BIT(7)
> +#define DS1388_REG_CONTROL		0x0c
> +#	define DS1388_BIT_RST		BIT(0)
> +#	define DS1388_BIT_WDE		BIT(1)
> +
>  /* negative offset step is -2.034ppm */
>  #define M41TXX_NEG_OFFSET_STEP_PPB	2034
>  /* positive offset step is +4.068ppm */
> @@ -166,6 +174,9 @@ struct ds1307 {
>  #ifdef CONFIG_COMMON_CLK
>  	struct clk_hw		clks[2];
>  #endif
> +#ifdef CONFIG_WATCHDOG_CORE
> +	struct watchdog_device	wdt;
> +#endif

I don't immediately see why this would be necessary. I think it would
be better to allocate struct watchdog_device in ds1307_wdt_register().

>  };
>  
>  struct chip_desc {
> @@ -854,6 +865,58 @@ static int m41txx_rtc_set_offset(struct device *dev, long offset)
>  				  ctrl_reg);
>  }
>  
> +#ifdef CONFIG_WATCHDOG_CORE
> +static int ds1388_wdt_start(struct watchdog_device *wdt_dev)
> +{
> +	struct ds1307 *ds1307 = watchdog_get_drvdata(wdt_dev);
> +	u8 regs[2];
> +	int ret;
> +
> +	ret = regmap_update_bits(ds1307->regmap, DS1388_REG_FLAG,
> +				 DS1388_BIT_WF, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(ds1307->regmap, DS1388_REG_CONTROL,
> +				 DS1388_BIT_WDE | DS1388_BIT_RST, 0);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * watchdog timeouts are measured in seconds. So ignore hundreths of

hundredths

> +	 * seconds field.
> +	 */
> +	regs[0] = 0;
> +	regs[1] = bin2bcd(wdt_dev->timeout);
> +
> +	ret = regmap_bulk_write(ds1307->regmap, DS1388_REG_WDOG_HUN_SECS, regs,
> +				sizeof(regs));
> +	if (ret)
> +		return ret;
> +
> +	return regmap_update_bits(ds1307->regmap, DS1388_REG_CONTROL,
> +				  DS1388_BIT_WDE | DS1388_BIT_RST,
> +				  DS1388_BIT_WDE | DS1388_BIT_RST);
> +}
> +
> +static int ds1388_wdt_stop(struct watchdog_device *wdt_dev)
> +{
> +	struct ds1307 *ds1307 = watchdog_get_drvdata(wdt_dev);
> +
> +	return regmap_update_bits(ds1307->regmap, DS1388_REG_CONTROL,
> +				  DS1388_BIT_WDE | DS1388_BIT_RST, 0);
> +}
> +
> +static int ds1388_wdt_ping(struct watchdog_device *wdt_dev)
> +{
> +	struct ds1307 *ds1307 = watchdog_get_drvdata(wdt_dev);
> +	u8 regs[2];
> +
> +	return regmap_bulk_read(ds1307->regmap, DS1388_REG_WDOG_HUN_SECS, regs,
> +				sizeof(regs));
> +}
> +#endif
> +
>  static const struct rtc_class_ops rx8130_rtc_ops = {
>  	.read_time      = ds1307_get_time,
>  	.set_time       = ds1307_set_time,
> @@ -1576,6 +1639,39 @@ static void ds1307_clks_register(struct ds1307 *ds1307)
>  
>  #endif /* CONFIG_COMMON_CLK */
>  
> +#ifdef CONFIG_WATCHDOG_CORE
> +static const struct watchdog_info ds1388_wdt_info = {
> +	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
> +	.identity = "DS1388 watchdog",
> +};
> +
> +static const struct watchdog_ops ds1388_wdt_ops = {
> +	.owner = THIS_MODULE,
> +	.start = ds1388_wdt_start,
> +	.stop = ds1388_wdt_stop,
> +	.ping = ds1388_wdt_ping,

Maybe I am missing something, but I don't see how the timeout is updated
if it is changed while the watchdog is already running.

> +};
> +
> +static void ds1307_wdt_register(struct ds1307 *ds1307)
> +{
> +	if (ds1307->type != ds_1388)
> +		return;
> +
> +	ds1307->wdt.info = &ds1388_wdt_info;
> +	ds1307->wdt.ops = &ds1388_wdt_ops;
> +	ds1307->wdt.max_timeout = 99;
> +	ds1307->wdt.min_timeout = 1;
> +
> +	watchdog_init_timeout(&ds1307->wdt, 99, ds1307->dev);

That is quite pointless; just set wdt.timeout to 99 (assuming
that is what you want as default).

watchdog_init_timeout() only makes sense if it is used to set the
timeout from a module parameter or from a devicetree property.

> +	watchdog_set_drvdata(&ds1307->wdt, ds1307);
> +	watchdog_register_device(&ds1307->wdt);

Please call devm_watchdog_register_device().

> +}
> +#else
> +static void ds1307_wdt_register(struct ds1307 *ds1307)
> +{
> +}
> +#endif /* CONFIG_WATCHDOG_CORE */
> +
>  static const struct regmap_config regmap_config = {
>  	.reg_bits = 8,
>  	.val_bits = 8,
> @@ -1865,6 +1961,7 @@ static int ds1307_probe(struct i2c_client *client,
>  
>  	ds1307_hwmon_register(ds1307);
>  	ds1307_clks_register(ds1307);
> +	ds1307_wdt_register(ds1307);
>  
>  	return 0;
>  
> 


      reply	other threads:[~2020-03-27 21:12 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-27  4:18 [PATCH v2] rtc: ds1307: add support for watchdog timer on ds1388 Chris Packham
2020-03-27 21:12 ` Guenter Roeck [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4aecb77e-f635-9bfd-c2bd-21cb68fa333d@roeck-us.net \
    --to=linux@roeck-us.net \
    --cc=a.zummo@towertech.it \
    --cc=alexandre.belloni@bootlin.com \
    --cc=chris.packham@alliedtelesis.co.nz \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rtc@vger.kernel.org \
    --cc=linux-watchdog@vger.kernel.org \
    --cc=wim@linux-watchdog.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).