brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · 8d5f67a Raw
173 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * txx9wdt: A Hardware Watchdog Driver for TXx9 SoCs4 *5 * Copyright (C) 2007 Atsushi Nemoto <anemo@mba.ocn.ne.jp>6 */7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt9 10#include <linux/module.h>11#include <linux/moduleparam.h>12#include <linux/types.h>13#include <linux/watchdog.h>14#include <linux/init.h>15#include <linux/platform_device.h>16#include <linux/clk.h>17#include <linux/err.h>18#include <linux/io.h>19#include <asm/txx9tmr.h>20 21#define WD_TIMER_CCD	7		/* 1/256 */22#define WD_TIMER_CLK	(clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))23#define WD_MAX_TIMEOUT	((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)24#define TIMER_MARGIN	60		/* Default is 60 seconds */25 26static unsigned int timeout = TIMER_MARGIN;	/* in seconds */27module_param(timeout, uint, 0);28MODULE_PARM_DESC(timeout,29	"Watchdog timeout in seconds. "30	"(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), "31	"default=" __MODULE_STRING(TIMER_MARGIN) ")");32 33static bool nowayout = WATCHDOG_NOWAYOUT;34module_param(nowayout, bool, 0);35MODULE_PARM_DESC(nowayout,36	"Watchdog cannot be stopped once started "37	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");38 39static struct txx9_tmr_reg __iomem *txx9wdt_reg;40static struct clk *txx9_imclk;41static DEFINE_SPINLOCK(txx9_lock);42 43static int txx9wdt_ping(struct watchdog_device *wdt_dev)44{45	spin_lock(&txx9_lock);46	__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);47	spin_unlock(&txx9_lock);48	return 0;49}50 51static int txx9wdt_start(struct watchdog_device *wdt_dev)52{53	spin_lock(&txx9_lock);54	__raw_writel(WD_TIMER_CLK * wdt_dev->timeout, &txx9wdt_reg->cpra);55	__raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);56	__raw_writel(0, &txx9wdt_reg->tisr);	/* clear pending interrupt */57	__raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,58		     &txx9wdt_reg->tcr);59	__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);60	spin_unlock(&txx9_lock);61	return 0;62}63 64static int txx9wdt_stop(struct watchdog_device *wdt_dev)65{66	spin_lock(&txx9_lock);67	__raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);68	__raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,69		     &txx9wdt_reg->tcr);70	spin_unlock(&txx9_lock);71	return 0;72}73 74static int txx9wdt_set_timeout(struct watchdog_device *wdt_dev,75			       unsigned int new_timeout)76{77	wdt_dev->timeout = new_timeout;78	txx9wdt_stop(wdt_dev);79	txx9wdt_start(wdt_dev);80	return 0;81}82 83static const struct watchdog_info txx9wdt_info = {84	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,85	.identity = "Hardware Watchdog for TXx9",86};87 88static const struct watchdog_ops txx9wdt_ops = {89	.owner = THIS_MODULE,90	.start = txx9wdt_start,91	.stop = txx9wdt_stop,92	.ping = txx9wdt_ping,93	.set_timeout = txx9wdt_set_timeout,94};95 96static struct watchdog_device txx9wdt = {97	.info = &txx9wdt_info,98	.ops = &txx9wdt_ops,99};100 101static int txx9wdt_probe(struct platform_device *dev)102{103	int ret;104 105	txx9_imclk = clk_get(NULL, "imbus_clk");106	if (IS_ERR(txx9_imclk)) {107		ret = PTR_ERR(txx9_imclk);108		txx9_imclk = NULL;109		goto exit;110	}111	ret = clk_prepare_enable(txx9_imclk);112	if (ret) {113		clk_put(txx9_imclk);114		txx9_imclk = NULL;115		goto exit;116	}117 118	txx9wdt_reg = devm_platform_ioremap_resource(dev, 0);119	if (IS_ERR(txx9wdt_reg)) {120		ret = PTR_ERR(txx9wdt_reg);121		goto exit;122	}123 124	if (timeout < 1 || timeout > WD_MAX_TIMEOUT)125		timeout = TIMER_MARGIN;126	txx9wdt.timeout = timeout;127	txx9wdt.min_timeout = 1;128	txx9wdt.max_timeout = WD_MAX_TIMEOUT;129	txx9wdt.parent = &dev->dev;130	watchdog_set_nowayout(&txx9wdt, nowayout);131 132	ret = watchdog_register_device(&txx9wdt);133	if (ret)134		goto exit;135 136	pr_info("Hardware Watchdog Timer: timeout=%d sec (max %ld) (nowayout= %d)\n",137		timeout, WD_MAX_TIMEOUT, nowayout);138 139	return 0;140exit:141	if (txx9_imclk) {142		clk_disable_unprepare(txx9_imclk);143		clk_put(txx9_imclk);144	}145	return ret;146}147 148static void txx9wdt_remove(struct platform_device *dev)149{150	watchdog_unregister_device(&txx9wdt);151	clk_disable_unprepare(txx9_imclk);152	clk_put(txx9_imclk);153}154 155static void txx9wdt_shutdown(struct platform_device *dev)156{157	txx9wdt_stop(&txx9wdt);158}159 160static struct platform_driver txx9wdt_driver = {161	.probe = txx9wdt_probe,162	.remove_new = txx9wdt_remove,163	.shutdown = txx9wdt_shutdown,164	.driver = {165		.name = "txx9wdt",166	},167};168module_platform_driver(txx9wdt_driver);169 170MODULE_DESCRIPTION("TXx9 Watchdog Driver");171MODULE_LICENSE("GPL");172MODULE_ALIAS("platform:txx9wdt");173