xref: /openbmc/linux/drivers/watchdog/twl4030_wdt.c (revision d36eda79c600518fb6bc8ad9e3f2f5f201ec1fb9)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
280e45b1eSTimo Kokkonen /*
380e45b1eSTimo Kokkonen  * Copyright (C) Nokia Corporation
480e45b1eSTimo Kokkonen  *
580e45b1eSTimo Kokkonen  * Written by Timo Kokkonen <timo.t.kokkonen at nokia.com>
680e45b1eSTimo Kokkonen  */
780e45b1eSTimo Kokkonen 
880e45b1eSTimo Kokkonen #include <linux/module.h>
980e45b1eSTimo Kokkonen #include <linux/types.h>
105a0e3ad6STejun Heo #include <linux/slab.h>
1180e45b1eSTimo Kokkonen #include <linux/kernel.h>
12099d387eSDmitry Torokhov #include <linux/mod_devicetable.h>
1380e45b1eSTimo Kokkonen #include <linux/watchdog.h>
1480e45b1eSTimo Kokkonen #include <linux/platform_device.h>
15a2054256SWolfram Sang #include <linux/mfd/twl.h>
1680e45b1eSTimo Kokkonen 
1780e45b1eSTimo Kokkonen #define TWL4030_WATCHDOG_CFG_REG_OFFS	0x3
1880e45b1eSTimo Kokkonen 
1986a1e189SWim Van Sebroeck static bool nowayout = WATCHDOG_NOWAYOUT;
2086a1e189SWim Van Sebroeck module_param(nowayout, bool, 0);
2180e45b1eSTimo Kokkonen MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
2280e45b1eSTimo Kokkonen 	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
2380e45b1eSTimo Kokkonen 
2480e45b1eSTimo Kokkonen static int twl4030_wdt_write(unsigned char val)
2580e45b1eSTimo Kokkonen {
262bc3f62fSPeter Ujfalusi 	return twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, val,
2780e45b1eSTimo Kokkonen 					TWL4030_WATCHDOG_CFG_REG_OFFS);
2880e45b1eSTimo Kokkonen }
2980e45b1eSTimo Kokkonen 
30b2c4e4b2SJarkko Nikula static int twl4030_wdt_start(struct watchdog_device *wdt)
3180e45b1eSTimo Kokkonen {
32b2c4e4b2SJarkko Nikula 	return twl4030_wdt_write(wdt->timeout + 1);
3380e45b1eSTimo Kokkonen }
3480e45b1eSTimo Kokkonen 
35b2c4e4b2SJarkko Nikula static int twl4030_wdt_stop(struct watchdog_device *wdt)
3680e45b1eSTimo Kokkonen {
3780e45b1eSTimo Kokkonen 	return twl4030_wdt_write(0);
3880e45b1eSTimo Kokkonen }
3980e45b1eSTimo Kokkonen 
40b2c4e4b2SJarkko Nikula static int twl4030_wdt_set_timeout(struct watchdog_device *wdt,
41b2c4e4b2SJarkko Nikula 				   unsigned int timeout)
4280e45b1eSTimo Kokkonen {
43b2c4e4b2SJarkko Nikula 	wdt->timeout = timeout;
44b2c4e4b2SJarkko Nikula 	return 0;
4580e45b1eSTimo Kokkonen }
4680e45b1eSTimo Kokkonen 
47b2c4e4b2SJarkko Nikula static const struct watchdog_info twl4030_wdt_info = {
48fb1cbeaeSTony Lindgren 	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
4980e45b1eSTimo Kokkonen 	.identity = "TWL4030 Watchdog",
5080e45b1eSTimo Kokkonen };
5180e45b1eSTimo Kokkonen 
52b2c4e4b2SJarkko Nikula static const struct watchdog_ops twl4030_wdt_ops = {
5380e45b1eSTimo Kokkonen 	.owner		= THIS_MODULE,
54b2c4e4b2SJarkko Nikula 	.start		= twl4030_wdt_start,
55b2c4e4b2SJarkko Nikula 	.stop		= twl4030_wdt_stop,
56b2c4e4b2SJarkko Nikula 	.set_timeout	= twl4030_wdt_set_timeout,
5780e45b1eSTimo Kokkonen };
5880e45b1eSTimo Kokkonen 
592d991a16SBill Pemberton static int twl4030_wdt_probe(struct platform_device *pdev)
6080e45b1eSTimo Kokkonen {
61b42488bcSGuenter Roeck 	struct device *dev = &pdev->dev;
62b2c4e4b2SJarkko Nikula 	struct watchdog_device *wdt;
6380e45b1eSTimo Kokkonen 
64b42488bcSGuenter Roeck 	wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
6580e45b1eSTimo Kokkonen 	if (!wdt)
6680e45b1eSTimo Kokkonen 		return -ENOMEM;
6780e45b1eSTimo Kokkonen 
68b2c4e4b2SJarkko Nikula 	wdt->info		= &twl4030_wdt_info;
69b2c4e4b2SJarkko Nikula 	wdt->ops		= &twl4030_wdt_ops;
70b2c4e4b2SJarkko Nikula 	wdt->status		= 0;
71b2c4e4b2SJarkko Nikula 	wdt->timeout		= 30;
72b2c4e4b2SJarkko Nikula 	wdt->min_timeout	= 1;
73b2c4e4b2SJarkko Nikula 	wdt->max_timeout	= 30;
74b42488bcSGuenter Roeck 	wdt->parent = dev;
7580e45b1eSTimo Kokkonen 
76b2c4e4b2SJarkko Nikula 	watchdog_set_nowayout(wdt, nowayout);
7780e45b1eSTimo Kokkonen 	platform_set_drvdata(pdev, wdt);
7880e45b1eSTimo Kokkonen 
79b2c4e4b2SJarkko Nikula 	twl4030_wdt_stop(wdt);
8080e45b1eSTimo Kokkonen 
81b42488bcSGuenter Roeck 	return devm_watchdog_register_device(dev, wdt);
8280e45b1eSTimo Kokkonen }
8380e45b1eSTimo Kokkonen 
8480e45b1eSTimo Kokkonen static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
8580e45b1eSTimo Kokkonen {
86b2c4e4b2SJarkko Nikula 	struct watchdog_device *wdt = platform_get_drvdata(pdev);
87b2c4e4b2SJarkko Nikula 	if (watchdog_active(wdt))
88b2c4e4b2SJarkko Nikula 		return twl4030_wdt_stop(wdt);
8980e45b1eSTimo Kokkonen 
9080e45b1eSTimo Kokkonen 	return 0;
9180e45b1eSTimo Kokkonen }
9280e45b1eSTimo Kokkonen 
9380e45b1eSTimo Kokkonen static int twl4030_wdt_resume(struct platform_device *pdev)
9480e45b1eSTimo Kokkonen {
95b2c4e4b2SJarkko Nikula 	struct watchdog_device *wdt = platform_get_drvdata(pdev);
96b2c4e4b2SJarkko Nikula 	if (watchdog_active(wdt))
97b2c4e4b2SJarkko Nikula 		return twl4030_wdt_start(wdt);
9880e45b1eSTimo Kokkonen 
9980e45b1eSTimo Kokkonen 	return 0;
10080e45b1eSTimo Kokkonen }
10180e45b1eSTimo Kokkonen 
1028899b8d9SAaro Koskinen static const struct of_device_id twl_wdt_of_match[] = {
1038899b8d9SAaro Koskinen 	{ .compatible = "ti,twl4030-wdt", },
1048899b8d9SAaro Koskinen 	{ },
1058899b8d9SAaro Koskinen };
1068899b8d9SAaro Koskinen MODULE_DEVICE_TABLE(of, twl_wdt_of_match);
1078899b8d9SAaro Koskinen 
10880e45b1eSTimo Kokkonen static struct platform_driver twl4030_wdt_driver = {
10980e45b1eSTimo Kokkonen 	.probe		= twl4030_wdt_probe,
110*d36eda79SPaul Cercueil 	.suspend	= pm_ptr(twl4030_wdt_suspend),
111*d36eda79SPaul Cercueil 	.resume		= pm_ptr(twl4030_wdt_resume),
11280e45b1eSTimo Kokkonen 	.driver		= {
11380e45b1eSTimo Kokkonen 		.name		= "twl4030_wdt",
1148899b8d9SAaro Koskinen 		.of_match_table	= twl_wdt_of_match,
11580e45b1eSTimo Kokkonen 	},
11680e45b1eSTimo Kokkonen };
11780e45b1eSTimo Kokkonen 
118b8ec6118SAxel Lin module_platform_driver(twl4030_wdt_driver);
11980e45b1eSTimo Kokkonen 
12080e45b1eSTimo Kokkonen MODULE_AUTHOR("Nokia Corporation");
12180e45b1eSTimo Kokkonen MODULE_LICENSE("GPL");
12280e45b1eSTimo Kokkonen MODULE_ALIAS("platform:twl4030_wdt");
12380e45b1eSTimo Kokkonen 
124