From: Oleksij Rempel <fixed-term.Oleksij.Rempel@xxxxxxxxxxxx> this driver is needed to ping over ICC bus a watchdog. Signed-off-by: Oleksij Rempel <linux@xxxxxxxxxxxxxxxx> Signed-off-by: Oleksij Rempel <fixed-term.Oleksij.Rempel@xxxxxxxxxxxx> --- drivers/watchdog/Kconfig | 8 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/icc_wdt.c | 185 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 drivers/watchdog/icc_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 16f2023..7e52835 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -104,6 +104,14 @@ config GPIO_WATCHDOG If you say yes here you get support for watchdog device controlled through GPIO-line. +config ICC_WATCHDOG + tristate "ICC watchdog" + depends on ICC + select WATCHDOG_CORE + help + If you say yes here you get support for watchdog device + controlled through ICC bus. + config MENF21BMC_WATCHDOG tristate "MEN 14F021P00 BMC Watchdog" depends on MFD_MENF21BMC diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 5c19294..40451cc 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -181,6 +181,7 @@ obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o obj-$(CONFIG_DA9063_WATCHDOG) += da9063_wdt.o obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o +obj-$(CONFIG_ICC_WATCHDOG) += icc_wdt.o obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o diff --git a/drivers/watchdog/icc_wdt.c b/drivers/watchdog/icc_wdt.c new file mode 100644 index 0000000..a89dc15 --- /dev/null +++ b/drivers/watchdog/icc_wdt.c @@ -0,0 +1,185 @@ +/* + * Driver for RBCM INC Gen3 Watchdog. + * RBCM - Robert Bosch Car Multimedia GmbH + * INC - Inter node communication. + * Gen3 - Generation 3 products. + * Short: rig3 :) + * + * Copyright (C) Robert Bosch Car Multimedia GmbH + * Authors: + * Oleksij Rempel + * <fixed-term.Oleksij.Rempel@xxxxxxxxxxxx> + * <linux@xxxxxxxxxxxxxxxx> + * + * Licensed under GPLv2 or later. + */ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/reset.h> +#include <linux/watchdog.h> +#include <linux/icc/icc.h> + +struct icc_wdt_priv { + struct device *dev; + struct icc_device *iccd; + struct watchdog_device wdd; + + struct icc_trf trf; + bool check_pong; + atomic_t pong; +}; + +static int icc_wdt_feed(struct watchdog_device *wdd) +{ + struct icc_wdt_priv *priv = watchdog_get_drvdata(wdd); + struct icc_device *iccd = priv->iccd; + + if (priv->check_pong && atomic_read(&priv->pong)) + dev_warn_ratelimited(priv->dev, "making ping without getting pong\n"); + + atomic_set(&priv->pong, 1); + + return icc_trf_xmit(iccd->iccm, &priv->trf); +} + +static int icc_wdt_enable(struct watchdog_device *wdd) +{ + return 0; +} + +static int icc_wdt_stop(struct watchdog_device *wdd) +{ + return 0; +} + +static const struct watchdog_info icc_wdt_ident = { + .identity = "RBCM, Inc Gen3 WatchDog", +}; + +static struct watchdog_ops icc_wdt_ops = { + .owner = THIS_MODULE, + .start = icc_wdt_enable, + .stop = icc_wdt_stop, + .ping = icc_wdt_feed, +}; + +static int icc_wdt_rx_cb(struct icc_device *iccd, void *rx_buf, size_t size) +{ + struct icc_wdt_priv *priv = icc_get_drvdata(iccd); + + atomic_set(&priv->pong, 0); + + return 0; +} + +static int icc_wdt_int_trf(struct icc_wdt_priv *priv) +{ + struct icc_device *iccd = priv->iccd; + struct icc_trf *trf = &priv->trf; + + u8 *buf; + int ret; + + ret = icc_trf_alloc(iccd->iccm, trf, 9, 1); + if (ret) + return ret; + + buf = trf->data; + buf[0] = 0x62; + + return 0; +} + +static int icc_wdt_probe(struct icc_device *iccd) +{ + struct device *dev = &iccd->dev; + struct icc_wdt_priv *priv; + struct watchdog_device *wdd; + int ret; + + priv = devm_kzalloc(dev, sizeof(struct icc_wdt_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->iccd = iccd; + + wdd = &priv->wdd; + wdd->info = &icc_wdt_ident; + wdd->ops = &icc_wdt_ops; + wdd->min_timeout = 1; + wdd->max_timeout = 10; + wdd->parent = dev; + + icc_set_drvdata(iccd, priv); + icc_set_rxcb(iccd, icc_wdt_rx_cb); + watchdog_set_drvdata(wdd, priv); + + /* + * If 'timeout-sec' unspecified in devicetree, assume a 30 second + * default, unless the max timeout is less than 30 seconds, then use + * the max instead. + */ + watchdog_init_timeout(wdd, 10, dev); + + ret = watchdog_register_device(wdd); + if (ret) + return ret; + + ret = icc_wdt_int_trf(priv); + if (ret) + return ret; + + dev_info(dev, "Watchdog enabled\n"); + return 0; +} + +static int icc_wdt_remove(struct icc_device *iccd) +{ + struct icc_wdt_priv *priv = icc_get_drvdata(iccd); + + watchdog_unregister_device(&priv->wdd); + + return 0; +} + +static const struct of_device_id icc_wdt_of_match[] = { + { .compatible = "rbcm,inc-wdt-gen3" }, + {}, +}; +MODULE_DEVICE_TABLE(of, icc_wdt_of_match); + +static struct icc_driver icc_wdt_driver = { + .driver = { + .name = "inc-wdt-gen3", + .owner = THIS_MODULE, + .of_match_table = icc_wdt_of_match, + }, + .probe = icc_wdt_probe, + .remove = icc_wdt_remove, +}; + +static int __init icc_wdt_init(void) +{ + return icc_register_driver(&icc_wdt_driver); +} +module_init(icc_wdt_init); + +static void __exit icc_wdt_exit(void) +{ + icc_unregister_driver(&icc_wdt_driver); +} +module_exit(icc_wdt_exit); + +MODULE_DESCRIPTION("ICC WatchDog Driver"); +MODULE_AUTHOR("Oleksij Rempel <fixed-term.Oleksij.Rempel@xxxxxxxxxxxx>"); +MODULE_LICENSE("GPL"); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html