Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Realtek RTD129x watchdog
0003  *
0004  * Copyright (c) 2017 Andreas Färber
0005  *
0006  * SPDX-License-Identifier: GPL-2.0+
0007  */
0008 
0009 #include <linux/bitops.h>
0010 #include <linux/clk.h>
0011 #include <linux/io.h>
0012 #include <linux/of.h>
0013 #include <linux/of_address.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/watchdog.h>
0016 
0017 #define RTD119X_TCWCR       0x0
0018 #define RTD119X_TCWTR       0x4
0019 #define RTD119X_TCWOV       0xc
0020 
0021 #define RTD119X_TCWCR_WDEN_DISABLED     0xa5
0022 #define RTD119X_TCWCR_WDEN_ENABLED      0xff
0023 #define RTD119X_TCWCR_WDEN_MASK         0xff
0024 
0025 #define RTD119X_TCWTR_WDCLR         BIT(0)
0026 
0027 struct rtd119x_watchdog_device {
0028     struct watchdog_device wdt_dev;
0029     void __iomem *base;
0030     struct clk *clk;
0031 };
0032 
0033 static int rtd119x_wdt_start(struct watchdog_device *wdev)
0034 {
0035     struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
0036     u32 val;
0037 
0038     val = readl_relaxed(data->base + RTD119X_TCWCR);
0039     val &= ~RTD119X_TCWCR_WDEN_MASK;
0040     val |= RTD119X_TCWCR_WDEN_ENABLED;
0041     writel(val, data->base + RTD119X_TCWCR);
0042 
0043     return 0;
0044 }
0045 
0046 static int rtd119x_wdt_stop(struct watchdog_device *wdev)
0047 {
0048     struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
0049     u32 val;
0050 
0051     val = readl_relaxed(data->base + RTD119X_TCWCR);
0052     val &= ~RTD119X_TCWCR_WDEN_MASK;
0053     val |= RTD119X_TCWCR_WDEN_DISABLED;
0054     writel(val, data->base + RTD119X_TCWCR);
0055 
0056     return 0;
0057 }
0058 
0059 static int rtd119x_wdt_ping(struct watchdog_device *wdev)
0060 {
0061     struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
0062 
0063     writel_relaxed(RTD119X_TCWTR_WDCLR, data->base + RTD119X_TCWTR);
0064 
0065     return rtd119x_wdt_start(wdev);
0066 }
0067 
0068 static int rtd119x_wdt_set_timeout(struct watchdog_device *wdev, unsigned int val)
0069 {
0070     struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
0071 
0072     writel(val * clk_get_rate(data->clk), data->base + RTD119X_TCWOV);
0073 
0074     data->wdt_dev.timeout = val;
0075 
0076     return 0;
0077 }
0078 
0079 static const struct watchdog_ops rtd119x_wdt_ops = {
0080     .owner = THIS_MODULE,
0081     .start      = rtd119x_wdt_start,
0082     .stop       = rtd119x_wdt_stop,
0083     .ping       = rtd119x_wdt_ping,
0084     .set_timeout    = rtd119x_wdt_set_timeout,
0085 };
0086 
0087 static const struct watchdog_info rtd119x_wdt_info = {
0088     .identity = "rtd119x-wdt",
0089     .options = 0,
0090 };
0091 
0092 static const struct of_device_id rtd119x_wdt_dt_ids[] = {
0093      { .compatible = "realtek,rtd1295-watchdog" },
0094      { }
0095 };
0096 
0097 static void rtd119x_clk_disable_unprepare(void *data)
0098 {
0099     clk_disable_unprepare(data);
0100 }
0101 
0102 static int rtd119x_wdt_probe(struct platform_device *pdev)
0103 {
0104     struct device *dev = &pdev->dev;
0105     struct rtd119x_watchdog_device *data;
0106     int ret;
0107 
0108     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0109     if (!data)
0110         return -ENOMEM;
0111 
0112     data->base = devm_platform_ioremap_resource(pdev, 0);
0113     if (IS_ERR(data->base))
0114         return PTR_ERR(data->base);
0115 
0116     data->clk = devm_clk_get(dev, NULL);
0117     if (IS_ERR(data->clk))
0118         return PTR_ERR(data->clk);
0119 
0120     ret = clk_prepare_enable(data->clk);
0121     if (ret)
0122         return ret;
0123     ret = devm_add_action_or_reset(dev, rtd119x_clk_disable_unprepare,
0124                        data->clk);
0125     if (ret)
0126         return ret;
0127 
0128     data->wdt_dev.info = &rtd119x_wdt_info;
0129     data->wdt_dev.ops = &rtd119x_wdt_ops;
0130     data->wdt_dev.timeout = 120;
0131     data->wdt_dev.max_timeout = 0xffffffff / clk_get_rate(data->clk);
0132     data->wdt_dev.min_timeout = 1;
0133     data->wdt_dev.parent = dev;
0134 
0135     watchdog_stop_on_reboot(&data->wdt_dev);
0136     watchdog_set_drvdata(&data->wdt_dev, data);
0137     platform_set_drvdata(pdev, data);
0138 
0139     writel_relaxed(RTD119X_TCWTR_WDCLR, data->base + RTD119X_TCWTR);
0140     rtd119x_wdt_set_timeout(&data->wdt_dev, data->wdt_dev.timeout);
0141     rtd119x_wdt_stop(&data->wdt_dev);
0142 
0143     return devm_watchdog_register_device(dev, &data->wdt_dev);
0144 }
0145 
0146 static struct platform_driver rtd119x_wdt_driver = {
0147     .probe = rtd119x_wdt_probe,
0148     .driver = {
0149         .name = "rtd1295-watchdog",
0150         .of_match_table = rtd119x_wdt_dt_ids,
0151     },
0152 };
0153 builtin_platform_driver(rtd119x_wdt_driver);