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