0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/err.h>
0013 #include <linux/init.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/mod_devicetable.h>
0017 #include <linux/mfd/max77620.h>
0018 #include <linux/mfd/max77714.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/regmap.h>
0021 #include <linux/slab.h>
0022 #include <linux/watchdog.h>
0023
0024 static bool nowayout = WATCHDOG_NOWAYOUT;
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 struct max77620_variant {
0037 u8 reg_onoff_cnfg2;
0038 u8 reg_cnfg_glbl2;
0039 u8 reg_cnfg_glbl3;
0040 u8 wdtc_mask;
0041 u8 bit_wd_rst_wk;
0042 u8 cnfg_glbl2_cfg_bits;
0043 };
0044
0045 struct max77620_wdt {
0046 struct device *dev;
0047 struct regmap *rmap;
0048 const struct max77620_variant *drv_data;
0049 struct watchdog_device wdt_dev;
0050 };
0051
0052 static const struct max77620_variant max77620_wdt_data = {
0053 .reg_onoff_cnfg2 = MAX77620_REG_ONOFFCNFG2,
0054 .reg_cnfg_glbl2 = MAX77620_REG_CNFGGLBL2,
0055 .reg_cnfg_glbl3 = MAX77620_REG_CNFGGLBL3,
0056 .wdtc_mask = MAX77620_WDTC_MASK,
0057 .bit_wd_rst_wk = MAX77620_ONOFFCNFG2_WD_RST_WK,
0058
0059 .cnfg_glbl2_cfg_bits = MAX77620_WDTSLPC | MAX77620_WDTOFFC,
0060 };
0061
0062 static const struct max77620_variant max77714_wdt_data = {
0063 .reg_onoff_cnfg2 = MAX77714_CNFG2_ONOFF,
0064 .reg_cnfg_glbl2 = MAX77714_CNFG_GLBL2,
0065 .reg_cnfg_glbl3 = MAX77714_CNFG_GLBL3,
0066 .wdtc_mask = MAX77714_WDTC,
0067 .bit_wd_rst_wk = MAX77714_WD_RST_WK,
0068
0069 .cnfg_glbl2_cfg_bits = MAX77714_WDTSLPC,
0070 };
0071
0072 static int max77620_wdt_start(struct watchdog_device *wdt_dev)
0073 {
0074 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
0075
0076 return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
0077 MAX77620_WDTEN, MAX77620_WDTEN);
0078 }
0079
0080 static int max77620_wdt_stop(struct watchdog_device *wdt_dev)
0081 {
0082 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
0083
0084 return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
0085 MAX77620_WDTEN, 0);
0086 }
0087
0088 static int max77620_wdt_ping(struct watchdog_device *wdt_dev)
0089 {
0090 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
0091
0092 return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,
0093 wdt->drv_data->wdtc_mask, 0x1);
0094 }
0095
0096 static int max77620_wdt_set_timeout(struct watchdog_device *wdt_dev,
0097 unsigned int timeout)
0098 {
0099 struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
0100 unsigned int wdt_timeout;
0101 u8 regval;
0102 int ret;
0103
0104 switch (timeout) {
0105 case 0 ... 2:
0106 regval = MAX77620_TWD_2s;
0107 wdt_timeout = 2;
0108 break;
0109
0110 case 3 ... 16:
0111 regval = MAX77620_TWD_16s;
0112 wdt_timeout = 16;
0113 break;
0114
0115 case 17 ... 64:
0116 regval = MAX77620_TWD_64s;
0117 wdt_timeout = 64;
0118 break;
0119
0120 default:
0121 regval = MAX77620_TWD_128s;
0122 wdt_timeout = 128;
0123 break;
0124 }
0125
0126
0127
0128
0129
0130
0131 ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,
0132 wdt->drv_data->wdtc_mask, 0x1);
0133 if (ret < 0)
0134 return ret;
0135
0136 ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
0137 MAX77620_TWD_MASK, regval);
0138 if (ret < 0)
0139 return ret;
0140
0141 wdt_dev->timeout = wdt_timeout;
0142
0143 return 0;
0144 }
0145
0146 static const struct watchdog_info max77620_wdt_info = {
0147 .identity = "max77620-watchdog",
0148 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
0149 };
0150
0151 static const struct watchdog_ops max77620_wdt_ops = {
0152 .start = max77620_wdt_start,
0153 .stop = max77620_wdt_stop,
0154 .ping = max77620_wdt_ping,
0155 .set_timeout = max77620_wdt_set_timeout,
0156 };
0157
0158 static int max77620_wdt_probe(struct platform_device *pdev)
0159 {
0160 const struct platform_device_id *id = platform_get_device_id(pdev);
0161 struct device *dev = &pdev->dev;
0162 struct max77620_wdt *wdt;
0163 struct watchdog_device *wdt_dev;
0164 unsigned int regval;
0165 int ret;
0166
0167 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
0168 if (!wdt)
0169 return -ENOMEM;
0170
0171 wdt->dev = dev;
0172 wdt->drv_data = (const struct max77620_variant *) id->driver_data;
0173
0174 wdt->rmap = dev_get_regmap(dev->parent, NULL);
0175 if (!wdt->rmap) {
0176 dev_err(wdt->dev, "Failed to get parent regmap\n");
0177 return -ENODEV;
0178 }
0179
0180 wdt_dev = &wdt->wdt_dev;
0181 wdt_dev->info = &max77620_wdt_info;
0182 wdt_dev->ops = &max77620_wdt_ops;
0183 wdt_dev->min_timeout = 2;
0184 wdt_dev->max_timeout = 128;
0185 wdt_dev->max_hw_heartbeat_ms = 128 * 1000;
0186
0187 platform_set_drvdata(pdev, wdt);
0188
0189
0190 ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_onoff_cnfg2,
0191 wdt->drv_data->bit_wd_rst_wk,
0192 wdt->drv_data->bit_wd_rst_wk);
0193 if (ret < 0) {
0194 dev_err(wdt->dev, "Failed to set WD_RST_WK: %d\n", ret);
0195 return ret;
0196 }
0197
0198
0199 ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
0200 wdt->drv_data->cnfg_glbl2_cfg_bits,
0201 wdt->drv_data->cnfg_glbl2_cfg_bits);
0202 if (ret < 0) {
0203 dev_err(wdt->dev, "Failed to set WDT OFF mode: %d\n", ret);
0204 return ret;
0205 }
0206
0207
0208 ret = regmap_read(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2, ®val);
0209 if (ret < 0) {
0210 dev_err(wdt->dev, "Failed to read WDT CFG register: %d\n", ret);
0211 return ret;
0212 }
0213
0214 switch (regval & MAX77620_TWD_MASK) {
0215 case MAX77620_TWD_2s:
0216 wdt_dev->timeout = 2;
0217 break;
0218 case MAX77620_TWD_16s:
0219 wdt_dev->timeout = 16;
0220 break;
0221 case MAX77620_TWD_64s:
0222 wdt_dev->timeout = 64;
0223 break;
0224 default:
0225 wdt_dev->timeout = 128;
0226 break;
0227 }
0228
0229 if (regval & MAX77620_WDTEN)
0230 set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
0231
0232 watchdog_set_nowayout(wdt_dev, nowayout);
0233 watchdog_set_drvdata(wdt_dev, wdt);
0234
0235 watchdog_stop_on_unregister(wdt_dev);
0236 return devm_watchdog_register_device(dev, wdt_dev);
0237 }
0238
0239 static const struct platform_device_id max77620_wdt_devtype[] = {
0240 { "max77620-watchdog", (kernel_ulong_t)&max77620_wdt_data },
0241 { "max77714-watchdog", (kernel_ulong_t)&max77714_wdt_data },
0242 { },
0243 };
0244 MODULE_DEVICE_TABLE(platform, max77620_wdt_devtype);
0245
0246 static struct platform_driver max77620_wdt_driver = {
0247 .driver = {
0248 .name = "max77620-watchdog",
0249 },
0250 .probe = max77620_wdt_probe,
0251 .id_table = max77620_wdt_devtype,
0252 };
0253
0254 module_platform_driver(max77620_wdt_driver);
0255
0256 MODULE_DESCRIPTION("Max77620 watchdog timer driver");
0257
0258 module_param(nowayout, bool, 0);
0259 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
0260 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0261
0262 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
0263 MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
0264 MODULE_LICENSE("GPL v2");