From: Guenter Roeck <linux@roeck-us.net>
To: Thomas Kastner <thomas.kastner@advantech.com>,
linux-watchdog@vger.kernel.org
Subject: Re: [PATCH v4 20221019] watchdog: Add Advantech EC watchdog driver
Date: Wed, 19 Oct 2022 17:56:52 -0700 [thread overview]
Message-ID: <b428bc31-2ff7-e6c7-33fa-96457ee7ba93@roeck-us.net> (raw)
In-Reply-To: <Y0+pl/26e3pcEUPk@EIS-S230>
On 10/19/22 00:39, Thomas Kastner wrote:
> This patch adds the 'advantech_ec_wdt' kernel module which provides
> WDT support for Advantech platforms with ITE based Embedded Controller.
>
> Signed-off-by: Thomas Kastner <thomas.kastner@advantech.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> ---
>
> v4:
> - fixed typo in MODULE_AUTHOR email address
>
It is not necessary to drop a Reviewed-by: tag for such a cosmetic change.
Thanks,
Guenter
> v3:
> - removed author email and disclaimer in file header
> - changed EC_ADDR_DATA/CMD to be based on EC_BASE_ADDR instead of fixed
> - fixed checkpatch.pl reported issues
> long line preferred over "quoted strings split across lines" due to grep
>
> v2:
> - added accessor function for EC IO access to remove unnecessary waits
> - moved EC probe to adv_ec_wdt_init()
> - implemented cosmetic changes found in the code review
> - removed debug output and unnecessary error messages
>
> v1:
> - initial version
>
> drivers/watchdog/Kconfig | 7 +
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/advantech_ec_wdt.c | 205 ++++++++++++++++++++++++++++
> 3 files changed, 213 insertions(+)
> create mode 100644 drivers/watchdog/advantech_ec_wdt.c
>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 688922fc4edb..a990016f791c 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -1055,6 +1055,13 @@ config ADVANTECH_WDT
> feature. More information can be found at
> <https://www.advantech.com.tw/products/>
>
> +config ADVANTECH_EC_WDT
> + tristate "Advantech Embedded Controller Watchdog Timer"
> + depends on X86
> + help
> + This driver supports Advantech products with ITE based Embedded Controller.
> + It does not support Advantech products with other ECs or without EC.
> +
> config ALIM1535_WDT
> tristate "ALi M1535 PMU Watchdog Timer"
> depends on X86 && PCI
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index cdeb119e6e61..2768dc2348af 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -102,6 +102,7 @@ obj-$(CONFIG_SUNPLUS_WATCHDOG) += sunplus_wdt.o
> # X86 (i386 + ia64 + x86_64) Architecture
> obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
> obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
> +obj-$(CONFIG_ADVANTECH_EC_WDT) += advantech_ec_wdt.o
> obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
> obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
> obj-$(CONFIG_EBC_C384_WDT) += ebc-c384_wdt.o
> diff --git a/drivers/watchdog/advantech_ec_wdt.c b/drivers/watchdog/advantech_ec_wdt.c
> new file mode 100644
> index 000000000000..7c380f90ca58
> --- /dev/null
> +++ b/drivers/watchdog/advantech_ec_wdt.c
> @@ -0,0 +1,205 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Advantech Embedded Controller Watchdog Driver
> + *
> + * This driver supports Advantech products with ITE based Embedded Controller.
> + * It does not support Advantech products with other ECs or without EC.
> + *
> + * Copyright (C) 2022 Advantech Europe B.V.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/isa.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/watchdog.h>
> +
> +#define DRIVER_NAME "advantech_ec_wdt"
> +
> +/* EC IO region */
> +#define EC_BASE_ADDR 0x299
> +#define EC_ADDR_EXTENT 2
> +
> +/* EC minimum IO access delay in ms */
> +#define EC_MIN_DELAY 10
> +
> +/* EC interface definitions */
> +#define EC_ADDR_CMD (EC_BASE_ADDR + 1)
> +#define EC_ADDR_DATA EC_BASE_ADDR
> +#define EC_CMD_EC_PROBE 0x30
> +#define EC_CMD_COMM 0x89
> +#define EC_CMD_WDT_START 0x28
> +#define EC_CMD_WDT_STOP 0x29
> +#define EC_CMD_WDT_RESET 0x2A
> +#define EC_DAT_EN_DLY_H 0x58
> +#define EC_DAT_EN_DLY_L 0x59
> +#define EC_DAT_RST_DLY_H 0x5E
> +#define EC_DAT_RST_DLY_L 0x5F
> +#define EC_MAGIC 0x95
> +
> +/* module parameters */
> +#define MIN_TIME 1
> +#define MAX_TIME 6000 /* 100 minutes */
> +#define DEFAULT_TIME 60
> +
> +static unsigned int timeout;
> +static ktime_t ec_timestamp;
> +
> +module_param(timeout, uint, 0);
> +MODULE_PARM_DESC(timeout,
> + "Default Watchdog timer setting (" __MODULE_STRING(DEFAULT_TIME) "s). The range is from " __MODULE_STRING(MIN_TIME) " to " __MODULE_STRING(MAX_TIME) ".");
> +
> +static void adv_ec_wdt_timing_gate(void)
> +{
> + ktime_t time_cur, time_delta;
> +
> + /* ensure minimum delay between IO accesses*/
> + time_cur = ktime_get();
> + time_delta = ktime_to_ms(ktime_sub(time_cur, ec_timestamp));
> + if (time_delta < EC_MIN_DELAY) {
> + time_delta = EC_MIN_DELAY - time_delta;
> + usleep_range(time_delta * 1000, (time_delta + 1) * 1000);
> + }
> + ec_timestamp = ktime_get();
> +}
> +
> +static void adv_ec_wdt_outb(unsigned char value, unsigned short port)
> +{
> + adv_ec_wdt_timing_gate();
> + outb(value, port);
> +}
> +
> +static unsigned char adv_ec_wdt_inb(unsigned short port)
> +{
> + adv_ec_wdt_timing_gate();
> + return inb(port);
> +}
> +
> +static int adv_ec_wdt_ping(struct watchdog_device *wdd)
> +{
> + adv_ec_wdt_outb(EC_CMD_WDT_RESET, EC_ADDR_CMD);
> + return 0;
> +}
> +
> +static int adv_ec_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
> +{
> + unsigned int val;
> +
> + /* scale time to EC 100 ms base */
> + val = t * 10;
> +
> + /* reset enable delay, just in case it was set by BIOS etc. */
> + adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
> + adv_ec_wdt_outb(EC_DAT_EN_DLY_H, EC_ADDR_DATA);
> + adv_ec_wdt_outb(0, EC_ADDR_DATA);
> +
> + adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
> + adv_ec_wdt_outb(EC_DAT_EN_DLY_L, EC_ADDR_DATA);
> + adv_ec_wdt_outb(0, EC_ADDR_DATA);
> +
> + /* set reset delay */
> + adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
> + adv_ec_wdt_outb(EC_DAT_RST_DLY_H, EC_ADDR_DATA);
> + adv_ec_wdt_outb(val >> 8, EC_ADDR_DATA);
> +
> + adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
> + adv_ec_wdt_outb(EC_DAT_RST_DLY_L, EC_ADDR_DATA);
> + adv_ec_wdt_outb(val & 0xFF, EC_ADDR_DATA);
> +
> + wdd->timeout = t;
> + return 0;
> +}
> +
> +static int adv_ec_wdt_start(struct watchdog_device *wdd)
> +{
> + adv_ec_wdt_set_timeout(wdd, wdd->timeout);
> + adv_ec_wdt_outb(EC_CMD_WDT_START, EC_ADDR_CMD);
> +
> + return 0;
> +}
> +
> +static int adv_ec_wdt_stop(struct watchdog_device *wdd)
> +{
> + adv_ec_wdt_outb(EC_CMD_WDT_STOP, EC_ADDR_CMD);
> +
> + return 0;
> +}
> +
> +static const struct watchdog_info adv_ec_wdt_info = {
> + .identity = DRIVER_NAME,
> + .options = WDIOF_SETTIMEOUT |
> + WDIOF_MAGICCLOSE |
> + WDIOF_KEEPALIVEPING,
> +};
> +
> +static const struct watchdog_ops adv_ec_wdt_ops = {
> + .owner = THIS_MODULE,
> + .start = adv_ec_wdt_start,
> + .stop = adv_ec_wdt_stop,
> + .ping = adv_ec_wdt_ping,
> + .set_timeout = adv_ec_wdt_set_timeout,
> +};
> +
> +static struct watchdog_device adv_ec_wdt_dev = {
> + .info = &adv_ec_wdt_info,
> + .ops = &adv_ec_wdt_ops,
> + .min_timeout = MIN_TIME,
> + .max_timeout = MAX_TIME,
> + .timeout = DEFAULT_TIME,
> +};
> +
> +static int adv_ec_wdt_probe(struct device *dev, unsigned int id)
> +{
> + if (!devm_request_region(dev, EC_BASE_ADDR, EC_ADDR_EXTENT, dev_name(dev))) {
> + dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
> + EC_BASE_ADDR, EC_BASE_ADDR + EC_ADDR_EXTENT);
> + return -EBUSY;
> + }
> +
> + watchdog_init_timeout(&adv_ec_wdt_dev, timeout, dev);
> + watchdog_stop_on_reboot(&adv_ec_wdt_dev);
> + watchdog_stop_on_unregister(&adv_ec_wdt_dev);
> +
> + return devm_watchdog_register_device(dev, &adv_ec_wdt_dev);
> +}
> +
> +static struct isa_driver adv_ec_wdt_driver = {
> + .probe = adv_ec_wdt_probe,
> + .driver = {
> + .name = DRIVER_NAME,
> + },
> +};
> +
> +static int __init adv_ec_wdt_init(void)
> +{
> + unsigned int val;
> +
> + /* quick probe for EC */
> + if (!request_region(EC_BASE_ADDR, EC_ADDR_EXTENT, DRIVER_NAME))
> + return -EBUSY;
> +
> + adv_ec_wdt_outb(EC_CMD_EC_PROBE, EC_ADDR_CMD);
> + val = adv_ec_wdt_inb(EC_ADDR_DATA);
> + release_region(EC_BASE_ADDR, EC_ADDR_EXTENT);
> +
> + if (val != EC_MAGIC)
> + return -ENODEV;
> +
> + return isa_register_driver(&adv_ec_wdt_driver, 1);
> +}
> +
> +static void __exit adv_ec_wdt_exit(void)
> +{
> + isa_unregister_driver(&adv_ec_wdt_driver);
> +}
> +
> +module_init(adv_ec_wdt_init);
> +module_exit(adv_ec_wdt_exit);
> +
> +MODULE_AUTHOR("Thomas Kastner <thomas.kastner@advantech.com>");
> +MODULE_DESCRIPTION("Advantech Embedded Controller Watchdog Device Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION("20221019");
> +MODULE_ALIAS("isa:" DRIVER_NAME);
next prev parent reply other threads:[~2022-10-20 0:56 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-19 7:39 [PATCH v4 20221019] watchdog: Add Advantech EC watchdog driver Thomas Kastner
2022-10-20 0:56 ` Guenter Roeck [this message]
2022-10-24 15:07 ` Thomas Kastner
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=b428bc31-2ff7-e6c7-33fa-96457ee7ba93@roeck-us.net \
--to=linux@roeck-us.net \
--cc=linux-watchdog@vger.kernel.org \
--cc=thomas.kastner@advantech.com \
/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 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.