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> 27*a2054256SWolfram Sang #include <linux/mfd/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 { 382bc3f62fSPeter 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 = { 60fb1cbeaeSTony Lindgren .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | 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; 866551881cSPratyush Anand wdt->parent = &pdev->dev; 8780e45b1eSTimo Kokkonen 88b2c4e4b2SJarkko Nikula watchdog_set_nowayout(wdt, nowayout); 8980e45b1eSTimo Kokkonen platform_set_drvdata(pdev, wdt); 9080e45b1eSTimo Kokkonen 91b2c4e4b2SJarkko Nikula twl4030_wdt_stop(wdt); 9280e45b1eSTimo Kokkonen 93b2c4e4b2SJarkko Nikula ret = watchdog_register_device(wdt); 946638f4e5SSachin Kamat if (ret) 9580e45b1eSTimo Kokkonen return ret; 96b2c4e4b2SJarkko Nikula 9780e45b1eSTimo Kokkonen return 0; 9880e45b1eSTimo Kokkonen } 9980e45b1eSTimo Kokkonen 1004b12b896SBill Pemberton static int twl4030_wdt_remove(struct platform_device *pdev) 10180e45b1eSTimo Kokkonen { 102b2c4e4b2SJarkko Nikula struct watchdog_device *wdt = platform_get_drvdata(pdev); 10380e45b1eSTimo Kokkonen 104b2c4e4b2SJarkko Nikula watchdog_unregister_device(wdt); 10580e45b1eSTimo Kokkonen 10680e45b1eSTimo Kokkonen return 0; 10780e45b1eSTimo Kokkonen } 10880e45b1eSTimo Kokkonen 10980e45b1eSTimo Kokkonen #ifdef CONFIG_PM 11080e45b1eSTimo Kokkonen static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state) 11180e45b1eSTimo Kokkonen { 112b2c4e4b2SJarkko Nikula struct watchdog_device *wdt = platform_get_drvdata(pdev); 113b2c4e4b2SJarkko Nikula if (watchdog_active(wdt)) 114b2c4e4b2SJarkko Nikula return twl4030_wdt_stop(wdt); 11580e45b1eSTimo Kokkonen 11680e45b1eSTimo Kokkonen return 0; 11780e45b1eSTimo Kokkonen } 11880e45b1eSTimo Kokkonen 11980e45b1eSTimo Kokkonen static int twl4030_wdt_resume(struct platform_device *pdev) 12080e45b1eSTimo Kokkonen { 121b2c4e4b2SJarkko Nikula struct watchdog_device *wdt = platform_get_drvdata(pdev); 122b2c4e4b2SJarkko Nikula if (watchdog_active(wdt)) 123b2c4e4b2SJarkko Nikula return twl4030_wdt_start(wdt); 12480e45b1eSTimo Kokkonen 12580e45b1eSTimo Kokkonen return 0; 12680e45b1eSTimo Kokkonen } 12780e45b1eSTimo Kokkonen #else 12880e45b1eSTimo Kokkonen #define twl4030_wdt_suspend NULL 12980e45b1eSTimo Kokkonen #define twl4030_wdt_resume NULL 13080e45b1eSTimo Kokkonen #endif 13180e45b1eSTimo Kokkonen 1328899b8d9SAaro Koskinen static const struct of_device_id twl_wdt_of_match[] = { 1338899b8d9SAaro Koskinen { .compatible = "ti,twl4030-wdt", }, 1348899b8d9SAaro Koskinen { }, 1358899b8d9SAaro Koskinen }; 1368899b8d9SAaro Koskinen MODULE_DEVICE_TABLE(of, twl_wdt_of_match); 1378899b8d9SAaro Koskinen 13880e45b1eSTimo Kokkonen static struct platform_driver twl4030_wdt_driver = { 13980e45b1eSTimo Kokkonen .probe = twl4030_wdt_probe, 14082268714SBill Pemberton .remove = twl4030_wdt_remove, 14180e45b1eSTimo Kokkonen .suspend = twl4030_wdt_suspend, 14280e45b1eSTimo Kokkonen .resume = twl4030_wdt_resume, 14380e45b1eSTimo Kokkonen .driver = { 14480e45b1eSTimo Kokkonen .name = "twl4030_wdt", 1458899b8d9SAaro Koskinen .of_match_table = twl_wdt_of_match, 14680e45b1eSTimo Kokkonen }, 14780e45b1eSTimo Kokkonen }; 14880e45b1eSTimo Kokkonen 149b8ec6118SAxel Lin module_platform_driver(twl4030_wdt_driver); 15080e45b1eSTimo Kokkonen 15180e45b1eSTimo Kokkonen MODULE_AUTHOR("Nokia Corporation"); 15280e45b1eSTimo Kokkonen MODULE_LICENSE("GPL"); 15380e45b1eSTimo Kokkonen MODULE_ALIAS("platform:twl4030_wdt"); 15480e45b1eSTimo Kokkonen 155