brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · cb4901b Raw
248 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Renesas RZ/A Series WDT Driver4 *5 * Copyright (C) 2017 Renesas Electronics America, Inc.6 * Copyright (C) 2017 Chris Brandt7 */8 9#include <linux/bitops.h>10#include <linux/clk.h>11#include <linux/delay.h>12#include <linux/io.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/watchdog.h>17 18#define DEFAULT_TIMEOUT		3019 20/* Watchdog Timer Registers */21#define WTCSR			022#define WTCSR_MAGIC		0xA50023#define WTSCR_WT		BIT(6)24#define WTSCR_TME		BIT(5)25#define WTSCR_CKS(i)		(i)26 27#define WTCNT			228#define WTCNT_MAGIC		0x5A0029 30#define WRCSR			431#define WRCSR_MAGIC		0x5A0032#define WRCSR_RSTE		BIT(6)33#define WRCSR_CLEAR_WOVF	0xA500	/* special value */34 35/* The maximum CKS register setting value to get the longest timeout */36#define CKS_3BIT		0x737#define CKS_4BIT		0xF38 39#define DIVIDER_3BIT		16384	/* Clock divider when CKS = 0x7 */40#define DIVIDER_4BIT		4194304	/* Clock divider when CKS = 0xF */41 42struct rza_wdt {43	struct watchdog_device wdev;44	void __iomem *base;45	struct clk *clk;46	u8 count;47	u8 cks;48};49 50static void rza_wdt_calc_timeout(struct rza_wdt *priv, int timeout)51{52	unsigned long rate = clk_get_rate(priv->clk);53	unsigned int ticks;54 55	if (priv->cks == CKS_4BIT) {56		ticks = DIV_ROUND_UP(timeout * rate, DIVIDER_4BIT);57 58		/*59		 * Since max_timeout was set in probe, we know that the timeout60		 * value passed will never calculate to a tick value greater61		 * than 256.62		 */63		priv->count = 256 - ticks;64 65	} else {66		/* Start timer with longest timeout */67		priv->count = 0;68	}69 70	pr_debug("%s: timeout set to %u (WTCNT=%d)\n", __func__,71		 timeout, priv->count);72}73 74static int rza_wdt_start(struct watchdog_device *wdev)75{76	struct rza_wdt *priv = watchdog_get_drvdata(wdev);77 78	/* Stop timer */79	writew(WTCSR_MAGIC | 0, priv->base + WTCSR);80 81	/* Must dummy read WRCSR:WOVF at least once before clearing */82	readb(priv->base + WRCSR);83	writew(WRCSR_CLEAR_WOVF, priv->base + WRCSR);84 85	rza_wdt_calc_timeout(priv, wdev->timeout);86 87	writew(WRCSR_MAGIC | WRCSR_RSTE, priv->base + WRCSR);88	writew(WTCNT_MAGIC | priv->count, priv->base + WTCNT);89	writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME |90	       WTSCR_CKS(priv->cks), priv->base + WTCSR);91 92	return 0;93}94 95static int rza_wdt_stop(struct watchdog_device *wdev)96{97	struct rza_wdt *priv = watchdog_get_drvdata(wdev);98 99	writew(WTCSR_MAGIC | 0, priv->base + WTCSR);100 101	return 0;102}103 104static int rza_wdt_ping(struct watchdog_device *wdev)105{106	struct rza_wdt *priv = watchdog_get_drvdata(wdev);107 108	writew(WTCNT_MAGIC | priv->count, priv->base + WTCNT);109 110	pr_debug("%s: timeout = %u\n", __func__, wdev->timeout);111 112	return 0;113}114 115static int rza_set_timeout(struct watchdog_device *wdev, unsigned int timeout)116{117	wdev->timeout = timeout;118	rza_wdt_start(wdev);119	return 0;120}121 122static int rza_wdt_restart(struct watchdog_device *wdev, unsigned long action,123			    void *data)124{125	struct rza_wdt *priv = watchdog_get_drvdata(wdev);126 127	/* Stop timer */128	writew(WTCSR_MAGIC | 0, priv->base + WTCSR);129 130	/* Must dummy read WRCSR:WOVF at least once before clearing */131	readb(priv->base + WRCSR);132	writew(WRCSR_CLEAR_WOVF, priv->base + WRCSR);133 134	/*135	 * Start timer with fastest clock source and only 1 clock left before136	 * overflow with reset option enabled.137	 */138	writew(WRCSR_MAGIC | WRCSR_RSTE, priv->base + WRCSR);139	writew(WTCNT_MAGIC | 255, priv->base + WTCNT);140	writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME, priv->base + WTCSR);141 142	/*143	 * Actually make sure the above sequence hits hardware before sleeping.144	 */145	wmb();146 147	/* Wait for WDT overflow (reset) */148	udelay(20);149 150	return 0;151}152 153static const struct watchdog_info rza_wdt_ident = {154	.options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,155	.identity = "Renesas RZ/A WDT Watchdog",156};157 158static const struct watchdog_ops rza_wdt_ops = {159	.owner = THIS_MODULE,160	.start = rza_wdt_start,161	.stop = rza_wdt_stop,162	.ping = rza_wdt_ping,163	.set_timeout = rza_set_timeout,164	.restart = rza_wdt_restart,165};166 167static int rza_wdt_probe(struct platform_device *pdev)168{169	struct device *dev = &pdev->dev;170	struct rza_wdt *priv;171	unsigned long rate;172	int ret;173 174	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);175	if (!priv)176		return -ENOMEM;177 178	priv->base = devm_platform_ioremap_resource(pdev, 0);179	if (IS_ERR(priv->base))180		return PTR_ERR(priv->base);181 182	priv->clk = devm_clk_get(dev, NULL);183	if (IS_ERR(priv->clk))184		return PTR_ERR(priv->clk);185 186	rate = clk_get_rate(priv->clk);187	if (rate < 16384) {188		dev_err(dev, "invalid clock rate (%ld)\n", rate);189		return -ENOENT;190	}191 192	priv->wdev.info = &rza_wdt_ident;193	priv->wdev.ops = &rza_wdt_ops;194	priv->wdev.parent = dev;195 196	priv->cks = (u8)(uintptr_t) of_device_get_match_data(dev);197	if (priv->cks == CKS_4BIT) {198		/* Assume slowest clock rate possible (CKS=0xF) */199		priv->wdev.max_timeout = (DIVIDER_4BIT * U8_MAX) / rate;200 201	} else if (priv->cks == CKS_3BIT) {202		/* Assume slowest clock rate possible (CKS=7) */203		rate /= DIVIDER_3BIT;204 205		/*206		 * Since the max possible timeout of our 8-bit count207		 * register is less than a second, we must use208		 * max_hw_heartbeat_ms.209		 */210		priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate;211		dev_dbg(dev, "max hw timeout of %dms\n",212			priv->wdev.max_hw_heartbeat_ms);213	}214 215	priv->wdev.min_timeout = 1;216	priv->wdev.timeout = DEFAULT_TIMEOUT;217 218	watchdog_init_timeout(&priv->wdev, 0, dev);219	watchdog_set_drvdata(&priv->wdev, priv);220 221	ret = devm_watchdog_register_device(dev, &priv->wdev);222	if (ret)223		dev_err(dev, "Cannot register watchdog device\n");224 225	return ret;226}227 228static const struct of_device_id rza_wdt_of_match[] = {229	{ .compatible = "renesas,r7s9210-wdt",	.data = (void *)CKS_4BIT, },230	{ .compatible = "renesas,rza-wdt",	.data = (void *)CKS_3BIT, },231	{ /* sentinel */ }232};233MODULE_DEVICE_TABLE(of, rza_wdt_of_match);234 235static struct platform_driver rza_wdt_driver = {236	.probe = rza_wdt_probe,237	.driver = {238		.name = "rza_wdt",239		.of_match_table = rza_wdt_of_match,240	},241};242 243module_platform_driver(rza_wdt_driver);244 245MODULE_DESCRIPTION("Renesas RZ/A WDT Driver");246MODULE_AUTHOR("Chris Brandt <chris.brandt@renesas.com>");247MODULE_LICENSE("GPL v2");248