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 21static bool nowayout = WATCHDOG_NOWAYOUT; 22 23struct max77620_wdt { 24 struct device *dev; 25 struct regmap *rmap; 26 struct watchdog_device wdt_dev; 27}; 28 29static 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 37static 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 45static 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 53static 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 98static const struct watchdog_info max77620_wdt_info = { 99 .identity = "max77620-watchdog", 100 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 101}; 102 103static 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 110static 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 188static const struct platform_device_id max77620_wdt_devtype[] = { 189 { .name = "max77620-watchdog", }, 190 { }, 191}; 192MODULE_DEVICE_TABLE(platform, max77620_wdt_devtype); 193 194static 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 202module_platform_driver(max77620_wdt_driver); 203 204MODULE_DESCRIPTION("Max77620 watchdog timer driver"); 205 206module_param(nowayout, bool, 0); 207MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 208 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 209 210MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 211MODULE_LICENSE("GPL v2"); 212