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