140 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Realtek RTD129x watchdog4 *5 * Copyright (c) 2017 Andreas Färber6 *7 */8 9#include <linux/bitops.h>10#include <linux/clk.h>11#include <linux/io.h>12#include <linux/of.h>13#include <linux/of_address.h>14#include <linux/platform_device.h>15#include <linux/watchdog.h>16 17#define RTD119X_TCWCR 0x018#define RTD119X_TCWTR 0x419#define RTD119X_TCWOV 0xc20 21#define RTD119X_TCWCR_WDEN_DISABLED 0xa522#define RTD119X_TCWCR_WDEN_ENABLED 0xff23#define RTD119X_TCWCR_WDEN_MASK 0xff24 25#define RTD119X_TCWTR_WDCLR BIT(0)26 27struct rtd119x_watchdog_device {28 struct watchdog_device wdt_dev;29 void __iomem *base;30 struct clk *clk;31};32 33static int rtd119x_wdt_start(struct watchdog_device *wdev)34{35 struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);36 u32 val;37 38 val = readl_relaxed(data->base + RTD119X_TCWCR);39 val &= ~RTD119X_TCWCR_WDEN_MASK;40 val |= RTD119X_TCWCR_WDEN_ENABLED;41 writel(val, data->base + RTD119X_TCWCR);42 43 return 0;44}45 46static int rtd119x_wdt_stop(struct watchdog_device *wdev)47{48 struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);49 u32 val;50 51 val = readl_relaxed(data->base + RTD119X_TCWCR);52 val &= ~RTD119X_TCWCR_WDEN_MASK;53 val |= RTD119X_TCWCR_WDEN_DISABLED;54 writel(val, data->base + RTD119X_TCWCR);55 56 return 0;57}58 59static int rtd119x_wdt_ping(struct watchdog_device *wdev)60{61 struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);62 63 writel_relaxed(RTD119X_TCWTR_WDCLR, data->base + RTD119X_TCWTR);64 65 return rtd119x_wdt_start(wdev);66}67 68static int rtd119x_wdt_set_timeout(struct watchdog_device *wdev, unsigned int val)69{70 struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);71 72 writel(val * clk_get_rate(data->clk), data->base + RTD119X_TCWOV);73 74 data->wdt_dev.timeout = val;75 76 return 0;77}78 79static const struct watchdog_ops rtd119x_wdt_ops = {80 .owner = THIS_MODULE,81 .start = rtd119x_wdt_start,82 .stop = rtd119x_wdt_stop,83 .ping = rtd119x_wdt_ping,84 .set_timeout = rtd119x_wdt_set_timeout,85};86 87static const struct watchdog_info rtd119x_wdt_info = {88 .identity = "rtd119x-wdt",89 .options = 0,90};91 92static const struct of_device_id rtd119x_wdt_dt_ids[] = {93 { .compatible = "realtek,rtd1295-watchdog" },94 { }95};96 97static int rtd119x_wdt_probe(struct platform_device *pdev)98{99 struct device *dev = &pdev->dev;100 struct rtd119x_watchdog_device *data;101 102 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);103 if (!data)104 return -ENOMEM;105 106 data->base = devm_platform_ioremap_resource(pdev, 0);107 if (IS_ERR(data->base))108 return PTR_ERR(data->base);109 110 data->clk = devm_clk_get_enabled(dev, NULL);111 if (IS_ERR(data->clk))112 return PTR_ERR(data->clk);113 114 data->wdt_dev.info = &rtd119x_wdt_info;115 data->wdt_dev.ops = &rtd119x_wdt_ops;116 data->wdt_dev.timeout = 120;117 data->wdt_dev.max_timeout = 0xffffffff / clk_get_rate(data->clk);118 data->wdt_dev.min_timeout = 1;119 data->wdt_dev.parent = dev;120 121 watchdog_stop_on_reboot(&data->wdt_dev);122 watchdog_set_drvdata(&data->wdt_dev, data);123 platform_set_drvdata(pdev, data);124 125 writel_relaxed(RTD119X_TCWTR_WDCLR, data->base + RTD119X_TCWTR);126 rtd119x_wdt_set_timeout(&data->wdt_dev, data->wdt_dev.timeout);127 rtd119x_wdt_stop(&data->wdt_dev);128 129 return devm_watchdog_register_device(dev, &data->wdt_dev);130}131 132static struct platform_driver rtd119x_wdt_driver = {133 .probe = rtd119x_wdt_probe,134 .driver = {135 .name = "rtd1295-watchdog",136 .of_match_table = rtd119x_wdt_dt_ids,137 },138};139builtin_platform_driver(rtd119x_wdt_driver);140