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/mfd/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_MAGICCLOSE | 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 wdt->parent = &pdev->dev; 87 88 watchdog_set_nowayout(wdt, nowayout); 89 platform_set_drvdata(pdev, wdt); 90 91 twl4030_wdt_stop(wdt); 92 93 ret = watchdog_register_device(wdt); 94 if (ret) 95 return ret; 96 97 return 0; 98 } 99 100 static int twl4030_wdt_remove(struct platform_device *pdev) 101 { 102 struct watchdog_device *wdt = platform_get_drvdata(pdev); 103 104 watchdog_unregister_device(wdt); 105 106 return 0; 107 } 108 109 #ifdef CONFIG_PM 110 static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state) 111 { 112 struct watchdog_device *wdt = platform_get_drvdata(pdev); 113 if (watchdog_active(wdt)) 114 return twl4030_wdt_stop(wdt); 115 116 return 0; 117 } 118 119 static int twl4030_wdt_resume(struct platform_device *pdev) 120 { 121 struct watchdog_device *wdt = platform_get_drvdata(pdev); 122 if (watchdog_active(wdt)) 123 return twl4030_wdt_start(wdt); 124 125 return 0; 126 } 127 #else 128 #define twl4030_wdt_suspend NULL 129 #define twl4030_wdt_resume NULL 130 #endif 131 132 static const struct of_device_id twl_wdt_of_match[] = { 133 { .compatible = "ti,twl4030-wdt", }, 134 { }, 135 }; 136 MODULE_DEVICE_TABLE(of, twl_wdt_of_match); 137 138 static struct platform_driver twl4030_wdt_driver = { 139 .probe = twl4030_wdt_probe, 140 .remove = twl4030_wdt_remove, 141 .suspend = twl4030_wdt_suspend, 142 .resume = twl4030_wdt_resume, 143 .driver = { 144 .name = "twl4030_wdt", 145 .of_match_table = twl_wdt_of_match, 146 }, 147 }; 148 149 module_platform_driver(twl4030_wdt_driver); 150 151 MODULE_AUTHOR("Nokia Corporation"); 152 MODULE_LICENSE("GPL"); 153 MODULE_ALIAS("platform:twl4030_wdt"); 154 155