265 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Maxim MAX77620 Watchdog Driver4 *5 * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.6 * Copyright (C) 2022 Luca Ceresoli7 *8 * Author: Laxman Dewangan <ldewangan@nvidia.com>9 * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>10 */11 12#include <linux/err.h>13#include <linux/init.h>14#include <linux/kernel.h>15#include <linux/module.h>16#include <linux/mod_devicetable.h>17#include <linux/mfd/max77620.h>18#include <linux/mfd/max77714.h>19#include <linux/platform_device.h>20#include <linux/regmap.h>21#include <linux/slab.h>22#include <linux/watchdog.h>23 24static bool nowayout = WATCHDOG_NOWAYOUT;25 26/**27 * struct max77620_variant - Data specific to a chip variant28 * @wdt_info: watchdog descriptor29 * @reg_onoff_cnfg2: ONOFF_CNFG2 register offset30 * @reg_cnfg_glbl2: CNFG_GLBL2 register offset31 * @reg_cnfg_glbl3: CNFG_GLBL3 register offset32 * @wdtc_mask: WDTC bit mask in CNFG_GLBL3 (=bits to update to ping the watchdog)33 * @bit_wd_rst_wk: WD_RST_WK bit offset within ONOFF_CNFG234 * @cnfg_glbl2_cfg_bits: configuration bits to enable in CNFG_GLBL2 register35 */36struct max77620_variant {37 u8 reg_onoff_cnfg2;38 u8 reg_cnfg_glbl2;39 u8 reg_cnfg_glbl3;40 u8 wdtc_mask;41 u8 bit_wd_rst_wk;42 u8 cnfg_glbl2_cfg_bits;43};44 45struct max77620_wdt {46 struct device *dev;47 struct regmap *rmap;48 const struct max77620_variant *drv_data;49 struct watchdog_device wdt_dev;50};51 52static const struct max77620_variant max77620_wdt_data = {53 .reg_onoff_cnfg2 = MAX77620_REG_ONOFFCNFG2,54 .reg_cnfg_glbl2 = MAX77620_REG_CNFGGLBL2,55 .reg_cnfg_glbl3 = MAX77620_REG_CNFGGLBL3,56 .wdtc_mask = MAX77620_WDTC_MASK,57 .bit_wd_rst_wk = MAX77620_ONOFFCNFG2_WD_RST_WK,58 /* Set WDT clear in OFF and sleep mode */59 .cnfg_glbl2_cfg_bits = MAX77620_WDTSLPC | MAX77620_WDTOFFC,60};61 62static const struct max77620_variant max77714_wdt_data = {63 .reg_onoff_cnfg2 = MAX77714_CNFG2_ONOFF,64 .reg_cnfg_glbl2 = MAX77714_CNFG_GLBL2,65 .reg_cnfg_glbl3 = MAX77714_CNFG_GLBL3,66 .wdtc_mask = MAX77714_WDTC,67 .bit_wd_rst_wk = MAX77714_WD_RST_WK,68 /* Set WDT clear in sleep mode (there is no WDTOFFC on MAX77714) */69 .cnfg_glbl2_cfg_bits = MAX77714_WDTSLPC,70};71 72static int max77620_wdt_start(struct watchdog_device *wdt_dev)73{74 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);75 76 return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,77 MAX77620_WDTEN, MAX77620_WDTEN);78}79 80static int max77620_wdt_stop(struct watchdog_device *wdt_dev)81{82 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);83 84 return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,85 MAX77620_WDTEN, 0);86}87 88static int max77620_wdt_ping(struct watchdog_device *wdt_dev)89{90 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);91 92 return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,93 wdt->drv_data->wdtc_mask, 0x1);94}95 96static int max77620_wdt_set_timeout(struct watchdog_device *wdt_dev,97 unsigned int timeout)98{99 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);100 unsigned int wdt_timeout;101 u8 regval;102 int ret;103 104 switch (timeout) {105 case 0 ... 2:106 regval = MAX77620_TWD_2s;107 wdt_timeout = 2;108 break;109 110 case 3 ... 16:111 regval = MAX77620_TWD_16s;112 wdt_timeout = 16;113 break;114 115 case 17 ... 64:116 regval = MAX77620_TWD_64s;117 wdt_timeout = 64;118 break;119 120 default:121 regval = MAX77620_TWD_128s;122 wdt_timeout = 128;123 break;124 }125 126 /*127 * "If the value of TWD needs to be changed, clear the system128 * watchdog timer first [...], then change the value of TWD."129 * (MAX77714 datasheet but applies to MAX77620 too)130 */131 ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,132 wdt->drv_data->wdtc_mask, 0x1);133 if (ret < 0)134 return ret;135 136 ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,137 MAX77620_TWD_MASK, regval);138 if (ret < 0)139 return ret;140 141 wdt_dev->timeout = wdt_timeout;142 143 return 0;144}145 146static const struct watchdog_info max77620_wdt_info = {147 .identity = "max77620-watchdog",148 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,149};150 151static const struct watchdog_ops max77620_wdt_ops = {152 .start = max77620_wdt_start,153 .stop = max77620_wdt_stop,154 .ping = max77620_wdt_ping,155 .set_timeout = max77620_wdt_set_timeout,156};157 158static int max77620_wdt_probe(struct platform_device *pdev)159{160 const struct platform_device_id *id = platform_get_device_id(pdev);161 struct device *dev = &pdev->dev;162 struct max77620_wdt *wdt;163 struct watchdog_device *wdt_dev;164 unsigned int regval;165 int ret;166 167 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);168 if (!wdt)169 return -ENOMEM;170 171 wdt->dev = dev;172 wdt->drv_data = (const struct max77620_variant *) id->driver_data;173 174 wdt->rmap = dev_get_regmap(dev->parent, NULL);175 if (!wdt->rmap) {176 dev_err(wdt->dev, "Failed to get parent regmap\n");177 return -ENODEV;178 }179 180 wdt_dev = &wdt->wdt_dev;181 wdt_dev->info = &max77620_wdt_info;182 wdt_dev->ops = &max77620_wdt_ops;183 wdt_dev->min_timeout = 2;184 wdt_dev->max_timeout = 128;185 wdt_dev->max_hw_heartbeat_ms = 128 * 1000;186 187 platform_set_drvdata(pdev, wdt);188 189 /* Enable WD_RST_WK - WDT expire results in a restart */190 ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_onoff_cnfg2,191 wdt->drv_data->bit_wd_rst_wk,192 wdt->drv_data->bit_wd_rst_wk);193 if (ret < 0) {194 dev_err(wdt->dev, "Failed to set WD_RST_WK: %d\n", ret);195 return ret;196 }197 198 /* Set the "auto WDT clear" bits available on the chip */199 ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,200 wdt->drv_data->cnfg_glbl2_cfg_bits,201 wdt->drv_data->cnfg_glbl2_cfg_bits);202 if (ret < 0) {203 dev_err(wdt->dev, "Failed to set WDT OFF mode: %d\n", ret);204 return ret;205 }206 207 /* Check if WDT running and if yes then set flags properly */208 ret = regmap_read(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2, ®val);209 if (ret < 0) {210 dev_err(wdt->dev, "Failed to read WDT CFG register: %d\n", ret);211 return ret;212 }213 214 switch (regval & MAX77620_TWD_MASK) {215 case MAX77620_TWD_2s:216 wdt_dev->timeout = 2;217 break;218 case MAX77620_TWD_16s:219 wdt_dev->timeout = 16;220 break;221 case MAX77620_TWD_64s:222 wdt_dev->timeout = 64;223 break;224 default:225 wdt_dev->timeout = 128;226 break;227 }228 229 if (regval & MAX77620_WDTEN)230 set_bit(WDOG_HW_RUNNING, &wdt_dev->status);231 232 watchdog_set_nowayout(wdt_dev, nowayout);233 watchdog_set_drvdata(wdt_dev, wdt);234 235 watchdog_stop_on_unregister(wdt_dev);236 return devm_watchdog_register_device(dev, wdt_dev);237}238 239static const struct platform_device_id max77620_wdt_devtype[] = {240 { "max77620-watchdog", (kernel_ulong_t)&max77620_wdt_data },241 { "max77714-watchdog", (kernel_ulong_t)&max77714_wdt_data },242 { },243};244MODULE_DEVICE_TABLE(platform, max77620_wdt_devtype);245 246static struct platform_driver max77620_wdt_driver = {247 .driver = {248 .name = "max77620-watchdog",249 },250 .probe = max77620_wdt_probe,251 .id_table = max77620_wdt_devtype,252};253 254module_platform_driver(max77620_wdt_driver);255 256MODULE_DESCRIPTION("Max77620 watchdog timer driver");257 258module_param(nowayout, bool, 0);259MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "260 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");261 262MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");263MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");264MODULE_LICENSE("GPL v2");265