125 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) Nokia Corporation4 *5 * Written by Timo Kokkonen <timo.t.kokkonen at nokia.com>6 */7 8#include <linux/module.h>9#include <linux/types.h>10#include <linux/slab.h>11#include <linux/kernel.h>12#include <linux/mod_devicetable.h>13#include <linux/watchdog.h>14#include <linux/platform_device.h>15#include <linux/mfd/twl.h>16 17#define TWL4030_WATCHDOG_CFG_REG_OFFS 0x318 19static bool nowayout = WATCHDOG_NOWAYOUT;20module_param(nowayout, bool, 0);21MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "22 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");23 24static int twl4030_wdt_write(unsigned char val)25{26 return twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, val,27 TWL4030_WATCHDOG_CFG_REG_OFFS);28}29 30static int twl4030_wdt_start(struct watchdog_device *wdt)31{32 return twl4030_wdt_write(wdt->timeout + 1);33}34 35static int twl4030_wdt_stop(struct watchdog_device *wdt)36{37 return twl4030_wdt_write(0);38}39 40static int twl4030_wdt_set_timeout(struct watchdog_device *wdt,41 unsigned int timeout)42{43 wdt->timeout = timeout;44 return 0;45}46 47static const struct watchdog_info twl4030_wdt_info = {48 .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,49 .identity = "TWL4030 Watchdog",50};51 52static const struct watchdog_ops twl4030_wdt_ops = {53 .owner = THIS_MODULE,54 .start = twl4030_wdt_start,55 .stop = twl4030_wdt_stop,56 .set_timeout = twl4030_wdt_set_timeout,57};58 59static int twl4030_wdt_probe(struct platform_device *pdev)60{61 struct device *dev = &pdev->dev;62 struct watchdog_device *wdt;63 64 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);65 if (!wdt)66 return -ENOMEM;67 68 wdt->info = &twl4030_wdt_info;69 wdt->ops = &twl4030_wdt_ops;70 wdt->status = 0;71 wdt->timeout = 30;72 wdt->min_timeout = 1;73 wdt->max_timeout = 30;74 wdt->parent = dev;75 76 watchdog_set_nowayout(wdt, nowayout);77 platform_set_drvdata(pdev, wdt);78 79 twl4030_wdt_stop(wdt);80 81 return devm_watchdog_register_device(dev, wdt);82}83 84static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)85{86 struct watchdog_device *wdt = platform_get_drvdata(pdev);87 if (watchdog_active(wdt))88 return twl4030_wdt_stop(wdt);89 90 return 0;91}92 93static int twl4030_wdt_resume(struct platform_device *pdev)94{95 struct watchdog_device *wdt = platform_get_drvdata(pdev);96 if (watchdog_active(wdt))97 return twl4030_wdt_start(wdt);98 99 return 0;100}101 102static const struct of_device_id twl_wdt_of_match[] = {103 { .compatible = "ti,twl4030-wdt", },104 { },105};106MODULE_DEVICE_TABLE(of, twl_wdt_of_match);107 108static struct platform_driver twl4030_wdt_driver = {109 .probe = twl4030_wdt_probe,110 .suspend = pm_ptr(twl4030_wdt_suspend),111 .resume = pm_ptr(twl4030_wdt_resume),112 .driver = {113 .name = "twl4030_wdt",114 .of_match_table = twl_wdt_of_match,115 },116};117 118module_platform_driver(twl4030_wdt_driver);119 120MODULE_AUTHOR("Nokia Corporation");121MODULE_DESCRIPTION("TWL4030 Watchdog");122MODULE_LICENSE("GPL");123MODULE_ALIAS("platform:twl4030_wdt");124 125