xref: /openbmc/linux/drivers/watchdog/twl4030_wdt.c (revision 2bc3f62f9627f136bb52b4cfa43060ef04656d2f)
180e45b1eSTimo Kokkonen /*
280e45b1eSTimo Kokkonen  * Copyright (C) Nokia Corporation
380e45b1eSTimo Kokkonen  *
480e45b1eSTimo Kokkonen  * Written by Timo Kokkonen <timo.t.kokkonen at nokia.com>
580e45b1eSTimo Kokkonen  *
680e45b1eSTimo Kokkonen  * This program is free software; you can redistribute it and/or modify
780e45b1eSTimo Kokkonen  * it under the terms of the GNU General Public License as published by
880e45b1eSTimo Kokkonen  * the Free Software Foundation; either version 2 of the License, or
980e45b1eSTimo Kokkonen  * (at your option) any later version.
1080e45b1eSTimo Kokkonen  *
1180e45b1eSTimo Kokkonen  * This program is distributed in the hope that it will be useful,
1280e45b1eSTimo Kokkonen  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1380e45b1eSTimo Kokkonen  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1480e45b1eSTimo Kokkonen  * GNU General Public License for more details.
1580e45b1eSTimo Kokkonen  *
1680e45b1eSTimo Kokkonen  * You should have received a copy of the GNU General Public License
1780e45b1eSTimo Kokkonen  * along with this program; if not, write to the Free Software
1880e45b1eSTimo Kokkonen  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1980e45b1eSTimo Kokkonen  */
2080e45b1eSTimo Kokkonen 
2180e45b1eSTimo Kokkonen #include <linux/module.h>
2280e45b1eSTimo Kokkonen #include <linux/types.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
2480e45b1eSTimo Kokkonen #include <linux/kernel.h>
2580e45b1eSTimo Kokkonen #include <linux/watchdog.h>
2680e45b1eSTimo Kokkonen #include <linux/platform_device.h>
27b07682b6SSantosh Shilimkar #include <linux/i2c/twl.h>
2880e45b1eSTimo Kokkonen 
2980e45b1eSTimo Kokkonen #define TWL4030_WATCHDOG_CFG_REG_OFFS	0x3
3080e45b1eSTimo Kokkonen 
3186a1e189SWim Van Sebroeck static bool nowayout = WATCHDOG_NOWAYOUT;
3286a1e189SWim Van Sebroeck module_param(nowayout, bool, 0);
3380e45b1eSTimo Kokkonen MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
3480e45b1eSTimo Kokkonen 	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
3580e45b1eSTimo Kokkonen 
3680e45b1eSTimo Kokkonen static int twl4030_wdt_write(unsigned char val)
3780e45b1eSTimo Kokkonen {
38*2bc3f62fSPeter Ujfalusi 	return twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, val,
3980e45b1eSTimo Kokkonen 					TWL4030_WATCHDOG_CFG_REG_OFFS);
4080e45b1eSTimo Kokkonen }
4180e45b1eSTimo Kokkonen 
42b2c4e4b2SJarkko Nikula static int twl4030_wdt_start(struct watchdog_device *wdt)
4380e45b1eSTimo Kokkonen {
44b2c4e4b2SJarkko Nikula 	return twl4030_wdt_write(wdt->timeout + 1);
4580e45b1eSTimo Kokkonen }
4680e45b1eSTimo Kokkonen 
47b2c4e4b2SJarkko Nikula static int twl4030_wdt_stop(struct watchdog_device *wdt)
4880e45b1eSTimo Kokkonen {
4980e45b1eSTimo Kokkonen 	return twl4030_wdt_write(0);
5080e45b1eSTimo Kokkonen }
5180e45b1eSTimo Kokkonen 
52b2c4e4b2SJarkko Nikula static int twl4030_wdt_set_timeout(struct watchdog_device *wdt,
53b2c4e4b2SJarkko Nikula 				   unsigned int timeout)
5480e45b1eSTimo Kokkonen {
55b2c4e4b2SJarkko Nikula 	wdt->timeout = timeout;
56b2c4e4b2SJarkko Nikula 	return 0;
5780e45b1eSTimo Kokkonen }
5880e45b1eSTimo Kokkonen 
59b2c4e4b2SJarkko Nikula static const struct watchdog_info twl4030_wdt_info = {
60b2c4e4b2SJarkko Nikula 	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
6180e45b1eSTimo Kokkonen 	.identity = "TWL4030 Watchdog",
6280e45b1eSTimo Kokkonen };
6380e45b1eSTimo Kokkonen 
64b2c4e4b2SJarkko Nikula static const struct watchdog_ops twl4030_wdt_ops = {
6580e45b1eSTimo Kokkonen 	.owner		= THIS_MODULE,
66b2c4e4b2SJarkko Nikula 	.start		= twl4030_wdt_start,
67b2c4e4b2SJarkko Nikula 	.stop		= twl4030_wdt_stop,
68b2c4e4b2SJarkko Nikula 	.set_timeout	= twl4030_wdt_set_timeout,
6980e45b1eSTimo Kokkonen };
7080e45b1eSTimo Kokkonen 
712d991a16SBill Pemberton static int twl4030_wdt_probe(struct platform_device *pdev)
7280e45b1eSTimo Kokkonen {
7380e45b1eSTimo Kokkonen 	int ret = 0;
74b2c4e4b2SJarkko Nikula 	struct watchdog_device *wdt;
7580e45b1eSTimo Kokkonen 
76b2c4e4b2SJarkko Nikula 	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
7780e45b1eSTimo Kokkonen 	if (!wdt)
7880e45b1eSTimo Kokkonen 		return -ENOMEM;
7980e45b1eSTimo Kokkonen 
80b2c4e4b2SJarkko Nikula 	wdt->info		= &twl4030_wdt_info;
81b2c4e4b2SJarkko Nikula 	wdt->ops		= &twl4030_wdt_ops;
82b2c4e4b2SJarkko Nikula 	wdt->status		= 0;
83b2c4e4b2SJarkko Nikula 	wdt->timeout		= 30;
84b2c4e4b2SJarkko Nikula 	wdt->min_timeout	= 1;
85b2c4e4b2SJarkko Nikula 	wdt->max_timeout	= 30;
8680e45b1eSTimo Kokkonen 
87b2c4e4b2SJarkko Nikula 	watchdog_set_nowayout(wdt, nowayout);
8880e45b1eSTimo Kokkonen 	platform_set_drvdata(pdev, wdt);
8980e45b1eSTimo Kokkonen 
90b2c4e4b2SJarkko Nikula 	twl4030_wdt_stop(wdt);
9180e45b1eSTimo Kokkonen 
92b2c4e4b2SJarkko Nikula 	ret = watchdog_register_device(wdt);
9380e45b1eSTimo Kokkonen 	if (ret) {
9480e45b1eSTimo Kokkonen 		platform_set_drvdata(pdev, NULL);
9580e45b1eSTimo Kokkonen 		return ret;
9680e45b1eSTimo Kokkonen 	}
97b2c4e4b2SJarkko Nikula 
9880e45b1eSTimo Kokkonen 	return 0;
9980e45b1eSTimo Kokkonen }
10080e45b1eSTimo Kokkonen 
1014b12b896SBill Pemberton static int twl4030_wdt_remove(struct platform_device *pdev)
10280e45b1eSTimo Kokkonen {
103b2c4e4b2SJarkko Nikula 	struct watchdog_device *wdt = platform_get_drvdata(pdev);
10480e45b1eSTimo Kokkonen 
105b2c4e4b2SJarkko Nikula 	watchdog_unregister_device(wdt);
10680e45b1eSTimo Kokkonen 	platform_set_drvdata(pdev, NULL);
10780e45b1eSTimo Kokkonen 
10880e45b1eSTimo Kokkonen 	return 0;
10980e45b1eSTimo Kokkonen }
11080e45b1eSTimo Kokkonen 
11180e45b1eSTimo Kokkonen #ifdef CONFIG_PM
11280e45b1eSTimo Kokkonen static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
11380e45b1eSTimo Kokkonen {
114b2c4e4b2SJarkko Nikula 	struct watchdog_device *wdt = platform_get_drvdata(pdev);
115b2c4e4b2SJarkko Nikula 	if (watchdog_active(wdt))
116b2c4e4b2SJarkko Nikula 		return twl4030_wdt_stop(wdt);
11780e45b1eSTimo Kokkonen 
11880e45b1eSTimo Kokkonen 	return 0;
11980e45b1eSTimo Kokkonen }
12080e45b1eSTimo Kokkonen 
12180e45b1eSTimo Kokkonen static int twl4030_wdt_resume(struct platform_device *pdev)
12280e45b1eSTimo Kokkonen {
123b2c4e4b2SJarkko Nikula 	struct watchdog_device *wdt = platform_get_drvdata(pdev);
124b2c4e4b2SJarkko Nikula 	if (watchdog_active(wdt))
125b2c4e4b2SJarkko Nikula 		return twl4030_wdt_start(wdt);
12680e45b1eSTimo Kokkonen 
12780e45b1eSTimo Kokkonen 	return 0;
12880e45b1eSTimo Kokkonen }
12980e45b1eSTimo Kokkonen #else
13080e45b1eSTimo Kokkonen #define twl4030_wdt_suspend        NULL
13180e45b1eSTimo Kokkonen #define twl4030_wdt_resume         NULL
13280e45b1eSTimo Kokkonen #endif
13380e45b1eSTimo Kokkonen 
13480e45b1eSTimo Kokkonen static struct platform_driver twl4030_wdt_driver = {
13580e45b1eSTimo Kokkonen 	.probe		= twl4030_wdt_probe,
13682268714SBill Pemberton 	.remove		= twl4030_wdt_remove,
13780e45b1eSTimo Kokkonen 	.suspend	= twl4030_wdt_suspend,
13880e45b1eSTimo Kokkonen 	.resume		= twl4030_wdt_resume,
13980e45b1eSTimo Kokkonen 	.driver		= {
14080e45b1eSTimo Kokkonen 		.owner	= THIS_MODULE,
14180e45b1eSTimo Kokkonen 		.name	= "twl4030_wdt",
14280e45b1eSTimo Kokkonen 	},
14380e45b1eSTimo Kokkonen };
14480e45b1eSTimo Kokkonen 
145b8ec6118SAxel Lin module_platform_driver(twl4030_wdt_driver);
14680e45b1eSTimo Kokkonen 
14780e45b1eSTimo Kokkonen MODULE_AUTHOR("Nokia Corporation");
14880e45b1eSTimo Kokkonen MODULE_LICENSE("GPL");
14980e45b1eSTimo Kokkonen MODULE_ALIAS("platform:twl4030_wdt");
15080e45b1eSTimo Kokkonen 
151