1 /* 2 * Maxim MAX77620 Watchdog Driver 3 * 4 * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. 5 * 6 * Author: Laxman Dewangan <ldewangan@nvidia.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/err.h> 14 #include <linux/init.h> 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/mod_devicetable.h> 18 #include <linux/mfd/max77620.h> 19 #include <linux/platform_device.h> 20 #include <linux/regmap.h> 21 #include <linux/slab.h> 22 #include <linux/watchdog.h> 23 24 static bool nowayout = WATCHDOG_NOWAYOUT; 25 26 struct max77620_wdt { 27 struct device *dev; 28 struct regmap *rmap; 29 struct watchdog_device wdt_dev; 30 }; 31 32 static int max77620_wdt_start(struct watchdog_device *wdt_dev) 33 { 34 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev); 35 36 return regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2, 37 MAX77620_WDTEN, MAX77620_WDTEN); 38 } 39 40 static int max77620_wdt_stop(struct watchdog_device *wdt_dev) 41 { 42 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev); 43 44 return regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2, 45 MAX77620_WDTEN, 0); 46 } 47 48 static int max77620_wdt_ping(struct watchdog_device *wdt_dev) 49 { 50 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev); 51 52 return regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL3, 53 MAX77620_WDTC_MASK, 0x1); 54 } 55 56 static int max77620_wdt_set_timeout(struct watchdog_device *wdt_dev, 57 unsigned int timeout) 58 { 59 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev); 60 unsigned int wdt_timeout; 61 u8 regval; 62 int ret; 63 64 switch (timeout) { 65 case 0 ... 2: 66 regval = MAX77620_TWD_2s; 67 wdt_timeout = 2; 68 break; 69 70 case 3 ... 16: 71 regval = MAX77620_TWD_16s; 72 wdt_timeout = 16; 73 break; 74 75 case 17 ... 64: 76 regval = MAX77620_TWD_64s; 77 wdt_timeout = 64; 78 break; 79 80 default: 81 regval = MAX77620_TWD_128s; 82 wdt_timeout = 128; 83 break; 84 } 85 86 ret = regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL3, 87 MAX77620_WDTC_MASK, 0x1); 88 if (ret < 0) 89 return ret; 90 91 ret = regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2, 92 MAX77620_TWD_MASK, regval); 93 if (ret < 0) 94 return ret; 95 96 wdt_dev->timeout = wdt_timeout; 97 98 return 0; 99 } 100 101 static const struct watchdog_info max77620_wdt_info = { 102 .identity = "max77620-watchdog", 103 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 104 }; 105 106 static const struct watchdog_ops max77620_wdt_ops = { 107 .start = max77620_wdt_start, 108 .stop = max77620_wdt_stop, 109 .ping = max77620_wdt_ping, 110 .set_timeout = max77620_wdt_set_timeout, 111 }; 112 113 static int max77620_wdt_probe(struct platform_device *pdev) 114 { 115 struct device *dev = &pdev->dev; 116 struct max77620_wdt *wdt; 117 struct watchdog_device *wdt_dev; 118 unsigned int regval; 119 int ret; 120 121 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); 122 if (!wdt) 123 return -ENOMEM; 124 125 wdt->dev = dev; 126 wdt->rmap = dev_get_regmap(dev->parent, NULL); 127 if (!wdt->rmap) { 128 dev_err(wdt->dev, "Failed to get parent regmap\n"); 129 return -ENODEV; 130 } 131 132 wdt_dev = &wdt->wdt_dev; 133 wdt_dev->info = &max77620_wdt_info; 134 wdt_dev->ops = &max77620_wdt_ops; 135 wdt_dev->min_timeout = 2; 136 wdt_dev->max_timeout = 128; 137 wdt_dev->max_hw_heartbeat_ms = 128 * 1000; 138 139 platform_set_drvdata(pdev, wdt); 140 141 /* Enable WD_RST_WK - WDT expire results in a restart */ 142 ret = regmap_update_bits(wdt->rmap, MAX77620_REG_ONOFFCNFG2, 143 MAX77620_ONOFFCNFG2_WD_RST_WK, 144 MAX77620_ONOFFCNFG2_WD_RST_WK); 145 if (ret < 0) { 146 dev_err(wdt->dev, "Failed to set WD_RST_WK: %d\n", ret); 147 return ret; 148 } 149 150 /* Set WDT clear in OFF and sleep mode */ 151 ret = regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2, 152 MAX77620_WDTOFFC | MAX77620_WDTSLPC, 153 MAX77620_WDTOFFC | MAX77620_WDTSLPC); 154 if (ret < 0) { 155 dev_err(wdt->dev, "Failed to set WDT OFF mode: %d\n", ret); 156 return ret; 157 } 158 159 /* Check if WDT running and if yes then set flags properly */ 160 ret = regmap_read(wdt->rmap, MAX77620_REG_CNFGGLBL2, ®val); 161 if (ret < 0) { 162 dev_err(wdt->dev, "Failed to read WDT CFG register: %d\n", ret); 163 return ret; 164 } 165 166 switch (regval & MAX77620_TWD_MASK) { 167 case MAX77620_TWD_2s: 168 wdt_dev->timeout = 2; 169 break; 170 case MAX77620_TWD_16s: 171 wdt_dev->timeout = 16; 172 break; 173 case MAX77620_TWD_64s: 174 wdt_dev->timeout = 64; 175 break; 176 default: 177 wdt_dev->timeout = 128; 178 break; 179 } 180 181 if (regval & MAX77620_WDTEN) 182 set_bit(WDOG_HW_RUNNING, &wdt_dev->status); 183 184 watchdog_set_nowayout(wdt_dev, nowayout); 185 watchdog_set_drvdata(wdt_dev, wdt); 186 187 watchdog_stop_on_unregister(wdt_dev); 188 ret = devm_watchdog_register_device(dev, wdt_dev); 189 if (ret < 0) { 190 dev_err(dev, "watchdog registration failed: %d\n", ret); 191 return ret; 192 } 193 194 return 0; 195 } 196 197 static const struct platform_device_id max77620_wdt_devtype[] = { 198 { .name = "max77620-watchdog", }, 199 { }, 200 }; 201 MODULE_DEVICE_TABLE(platform, max77620_wdt_devtype); 202 203 static struct platform_driver max77620_wdt_driver = { 204 .driver = { 205 .name = "max77620-watchdog", 206 }, 207 .probe = max77620_wdt_probe, 208 .id_table = max77620_wdt_devtype, 209 }; 210 211 module_platform_driver(max77620_wdt_driver); 212 213 MODULE_DESCRIPTION("Max77620 watchdog timer driver"); 214 215 module_param(nowayout, bool, 0); 216 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 217 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 218 219 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 220 MODULE_LICENSE("GPL v2"); 221