1 /* 2 * Copyright (C) Nokia Corporation 3 * 4 * Written by Timo Kokkonen <timo.t.kokkonen at nokia.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 #include <linux/module.h> 22 #include <linux/types.h> 23 #include <linux/slab.h> 24 #include <linux/kernel.h> 25 #include <linux/watchdog.h> 26 #include <linux/platform_device.h> 27 #include <linux/i2c/twl.h> 28 29 #define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3 30 31 static bool nowayout = WATCHDOG_NOWAYOUT; 32 module_param(nowayout, bool, 0); 33 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 34 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 35 36 static int twl4030_wdt_write(unsigned char val) 37 { 38 return twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, val, 39 TWL4030_WATCHDOG_CFG_REG_OFFS); 40 } 41 42 static int twl4030_wdt_start(struct watchdog_device *wdt) 43 { 44 return twl4030_wdt_write(wdt->timeout + 1); 45 } 46 47 static int twl4030_wdt_stop(struct watchdog_device *wdt) 48 { 49 return twl4030_wdt_write(0); 50 } 51 52 static int twl4030_wdt_set_timeout(struct watchdog_device *wdt, 53 unsigned int timeout) 54 { 55 wdt->timeout = timeout; 56 return 0; 57 } 58 59 static const struct watchdog_info twl4030_wdt_info = { 60 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 61 .identity = "TWL4030 Watchdog", 62 }; 63 64 static const struct watchdog_ops twl4030_wdt_ops = { 65 .owner = THIS_MODULE, 66 .start = twl4030_wdt_start, 67 .stop = twl4030_wdt_stop, 68 .set_timeout = twl4030_wdt_set_timeout, 69 }; 70 71 static int twl4030_wdt_probe(struct platform_device *pdev) 72 { 73 int ret = 0; 74 struct watchdog_device *wdt; 75 76 wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); 77 if (!wdt) 78 return -ENOMEM; 79 80 wdt->info = &twl4030_wdt_info; 81 wdt->ops = &twl4030_wdt_ops; 82 wdt->status = 0; 83 wdt->timeout = 30; 84 wdt->min_timeout = 1; 85 wdt->max_timeout = 30; 86 87 watchdog_set_nowayout(wdt, nowayout); 88 platform_set_drvdata(pdev, wdt); 89 90 twl4030_wdt_stop(wdt); 91 92 ret = watchdog_register_device(wdt); 93 if (ret) 94 return ret; 95 96 return 0; 97 } 98 99 static int twl4030_wdt_remove(struct platform_device *pdev) 100 { 101 struct watchdog_device *wdt = platform_get_drvdata(pdev); 102 103 watchdog_unregister_device(wdt); 104 105 return 0; 106 } 107 108 #ifdef CONFIG_PM 109 static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state) 110 { 111 struct watchdog_device *wdt = platform_get_drvdata(pdev); 112 if (watchdog_active(wdt)) 113 return twl4030_wdt_stop(wdt); 114 115 return 0; 116 } 117 118 static int twl4030_wdt_resume(struct platform_device *pdev) 119 { 120 struct watchdog_device *wdt = platform_get_drvdata(pdev); 121 if (watchdog_active(wdt)) 122 return twl4030_wdt_start(wdt); 123 124 return 0; 125 } 126 #else 127 #define twl4030_wdt_suspend NULL 128 #define twl4030_wdt_resume NULL 129 #endif 130 131 static const struct of_device_id twl_wdt_of_match[] = { 132 { .compatible = "ti,twl4030-wdt", }, 133 { }, 134 }; 135 MODULE_DEVICE_TABLE(of, twl_wdt_of_match); 136 137 static struct platform_driver twl4030_wdt_driver = { 138 .probe = twl4030_wdt_probe, 139 .remove = twl4030_wdt_remove, 140 .suspend = twl4030_wdt_suspend, 141 .resume = twl4030_wdt_resume, 142 .driver = { 143 .name = "twl4030_wdt", 144 .of_match_table = twl_wdt_of_match, 145 }, 146 }; 147 148 module_platform_driver(twl4030_wdt_driver); 149 150 MODULE_AUTHOR("Nokia Corporation"); 151 MODULE_LICENSE("GPL"); 152 MODULE_ALIAS("platform:twl4030_wdt"); 153 154