Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * ST's LPC Watchdog
0004  *
0005  * Copyright (C) 2014 STMicroelectronics -- All Rights Reserved
0006  *
0007  * Author: David Paris <david.paris@st.com> for STMicroelectronics
0008  *         Lee Jones <lee.jones@linaro.org> for STMicroelectronics
0009  */
0010 
0011 #include <linux/clk.h>
0012 #include <linux/init.h>
0013 #include <linux/io.h>
0014 #include <linux/kernel.h>
0015 #include <linux/mfd/syscon.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/of_platform.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/regmap.h>
0021 #include <linux/watchdog.h>
0022 
0023 #include <dt-bindings/mfd/st-lpc.h>
0024 
0025 /* Low Power Alarm */
0026 #define LPC_LPA_LSB_OFF         0x410
0027 #define LPC_LPA_START_OFF       0x418
0028 
0029 /* LPC as WDT */
0030 #define LPC_WDT_OFF         0x510
0031 
0032 static struct watchdog_device st_wdog_dev;
0033 
0034 struct st_wdog_syscfg {
0035     unsigned int reset_type_reg;
0036     unsigned int reset_type_mask;
0037     unsigned int enable_reg;
0038     unsigned int enable_mask;
0039 };
0040 
0041 struct st_wdog {
0042     void __iomem *base;
0043     struct device *dev;
0044     struct regmap *regmap;
0045     struct st_wdog_syscfg *syscfg;
0046     struct clk *clk;
0047     unsigned long clkrate;
0048     bool warm_reset;
0049 };
0050 
0051 static struct st_wdog_syscfg stih407_syscfg = {
0052     .enable_reg     = 0x204,
0053     .enable_mask        = BIT(19),
0054 };
0055 
0056 static const struct of_device_id st_wdog_match[] = {
0057     {
0058         .compatible = "st,stih407-lpc",
0059         .data = &stih407_syscfg,
0060     },
0061     {},
0062 };
0063 MODULE_DEVICE_TABLE(of, st_wdog_match);
0064 
0065 static void st_wdog_setup(struct st_wdog *st_wdog, bool enable)
0066 {
0067     /* Type of watchdog reset - 0: Cold 1: Warm */
0068     if (st_wdog->syscfg->reset_type_reg)
0069         regmap_update_bits(st_wdog->regmap,
0070                    st_wdog->syscfg->reset_type_reg,
0071                    st_wdog->syscfg->reset_type_mask,
0072                    st_wdog->warm_reset);
0073 
0074     /* Mask/unmask watchdog reset */
0075     regmap_update_bits(st_wdog->regmap,
0076                st_wdog->syscfg->enable_reg,
0077                st_wdog->syscfg->enable_mask,
0078                enable ? 0 : st_wdog->syscfg->enable_mask);
0079 }
0080 
0081 static void st_wdog_load_timer(struct st_wdog *st_wdog, unsigned int timeout)
0082 {
0083     unsigned long clkrate = st_wdog->clkrate;
0084 
0085     writel_relaxed(timeout * clkrate, st_wdog->base + LPC_LPA_LSB_OFF);
0086     writel_relaxed(1, st_wdog->base + LPC_LPA_START_OFF);
0087 }
0088 
0089 static int st_wdog_start(struct watchdog_device *wdd)
0090 {
0091     struct st_wdog *st_wdog = watchdog_get_drvdata(wdd);
0092 
0093     writel_relaxed(1, st_wdog->base + LPC_WDT_OFF);
0094 
0095     return 0;
0096 }
0097 
0098 static int st_wdog_stop(struct watchdog_device *wdd)
0099 {
0100     struct st_wdog *st_wdog = watchdog_get_drvdata(wdd);
0101 
0102     writel_relaxed(0, st_wdog->base + LPC_WDT_OFF);
0103 
0104     return 0;
0105 }
0106 
0107 static int st_wdog_set_timeout(struct watchdog_device *wdd,
0108                    unsigned int timeout)
0109 {
0110     struct st_wdog *st_wdog = watchdog_get_drvdata(wdd);
0111 
0112     wdd->timeout = timeout;
0113     st_wdog_load_timer(st_wdog, timeout);
0114 
0115     return 0;
0116 }
0117 
0118 static int st_wdog_keepalive(struct watchdog_device *wdd)
0119 {
0120     struct st_wdog *st_wdog = watchdog_get_drvdata(wdd);
0121 
0122     st_wdog_load_timer(st_wdog, wdd->timeout);
0123 
0124     return 0;
0125 }
0126 
0127 static const struct watchdog_info st_wdog_info = {
0128     .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
0129     .identity = "ST LPC WDT",
0130 };
0131 
0132 static const struct watchdog_ops st_wdog_ops = {
0133     .owner      = THIS_MODULE,
0134     .start      = st_wdog_start,
0135     .stop       = st_wdog_stop,
0136     .ping       = st_wdog_keepalive,
0137     .set_timeout    = st_wdog_set_timeout,
0138 };
0139 
0140 static struct watchdog_device st_wdog_dev = {
0141     .info       = &st_wdog_info,
0142     .ops        = &st_wdog_ops,
0143 };
0144 
0145 static void st_clk_disable_unprepare(void *data)
0146 {
0147     clk_disable_unprepare(data);
0148 }
0149 
0150 static int st_wdog_probe(struct platform_device *pdev)
0151 {
0152     struct device *dev = &pdev->dev;
0153     const struct of_device_id *match;
0154     struct device_node *np = dev->of_node;
0155     struct st_wdog *st_wdog;
0156     struct regmap *regmap;
0157     struct clk *clk;
0158     void __iomem *base;
0159     uint32_t mode;
0160     int ret;
0161 
0162     ret = of_property_read_u32(np, "st,lpc-mode", &mode);
0163     if (ret) {
0164         dev_err(dev, "An LPC mode must be provided\n");
0165         return -EINVAL;
0166     }
0167 
0168     /* LPC can either run as a Clocksource or in RTC or WDT mode */
0169     if (mode != ST_LPC_MODE_WDT)
0170         return -ENODEV;
0171 
0172     st_wdog = devm_kzalloc(dev, sizeof(*st_wdog), GFP_KERNEL);
0173     if (!st_wdog)
0174         return -ENOMEM;
0175 
0176     match = of_match_device(st_wdog_match, dev);
0177     if (!match) {
0178         dev_err(dev, "Couldn't match device\n");
0179         return -ENODEV;
0180     }
0181     st_wdog->syscfg = (struct st_wdog_syscfg *)match->data;
0182 
0183     base = devm_platform_ioremap_resource(pdev, 0);
0184     if (IS_ERR(base))
0185         return PTR_ERR(base);
0186 
0187     regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
0188     if (IS_ERR(regmap)) {
0189         dev_err(dev, "No syscfg phandle specified\n");
0190         return PTR_ERR(regmap);
0191     }
0192 
0193     clk = devm_clk_get(dev, NULL);
0194     if (IS_ERR(clk)) {
0195         dev_err(dev, "Unable to request clock\n");
0196         return PTR_ERR(clk);
0197     }
0198 
0199     st_wdog->dev        = dev;
0200     st_wdog->base       = base;
0201     st_wdog->clk        = clk;
0202     st_wdog->regmap     = regmap;
0203     st_wdog->warm_reset = of_property_read_bool(np, "st,warm_reset");
0204     st_wdog->clkrate    = clk_get_rate(st_wdog->clk);
0205 
0206     if (!st_wdog->clkrate) {
0207         dev_err(dev, "Unable to fetch clock rate\n");
0208         return -EINVAL;
0209     }
0210     st_wdog_dev.max_timeout = 0xFFFFFFFF / st_wdog->clkrate;
0211     st_wdog_dev.parent = dev;
0212 
0213     ret = clk_prepare_enable(clk);
0214     if (ret) {
0215         dev_err(dev, "Unable to enable clock\n");
0216         return ret;
0217     }
0218     ret = devm_add_action_or_reset(dev, st_clk_disable_unprepare, clk);
0219     if (ret)
0220         return ret;
0221 
0222     watchdog_set_drvdata(&st_wdog_dev, st_wdog);
0223     watchdog_set_nowayout(&st_wdog_dev, WATCHDOG_NOWAYOUT);
0224 
0225     /* Init Watchdog timeout with value in DT */
0226     ret = watchdog_init_timeout(&st_wdog_dev, 0, dev);
0227     if (ret)
0228         return ret;
0229 
0230     ret = devm_watchdog_register_device(dev, &st_wdog_dev);
0231     if (ret)
0232         return ret;
0233 
0234     st_wdog_setup(st_wdog, true);
0235 
0236     dev_info(dev, "LPC Watchdog driver registered, reset type is %s",
0237          st_wdog->warm_reset ? "warm" : "cold");
0238 
0239     return ret;
0240 }
0241 
0242 static int st_wdog_remove(struct platform_device *pdev)
0243 {
0244     struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev);
0245 
0246     st_wdog_setup(st_wdog, false);
0247 
0248     return 0;
0249 }
0250 
0251 static int st_wdog_suspend(struct device *dev)
0252 {
0253     struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev);
0254 
0255     if (watchdog_active(&st_wdog_dev))
0256         st_wdog_stop(&st_wdog_dev);
0257 
0258     st_wdog_setup(st_wdog, false);
0259 
0260     clk_disable(st_wdog->clk);
0261 
0262     return 0;
0263 }
0264 
0265 static int st_wdog_resume(struct device *dev)
0266 {
0267     struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev);
0268     int ret;
0269 
0270     ret = clk_enable(st_wdog->clk);
0271     if (ret) {
0272         dev_err(dev, "Unable to re-enable clock\n");
0273         watchdog_unregister_device(&st_wdog_dev);
0274         clk_unprepare(st_wdog->clk);
0275         return ret;
0276     }
0277 
0278     st_wdog_setup(st_wdog, true);
0279 
0280     if (watchdog_active(&st_wdog_dev)) {
0281         st_wdog_load_timer(st_wdog, st_wdog_dev.timeout);
0282         st_wdog_start(&st_wdog_dev);
0283     }
0284 
0285     return 0;
0286 }
0287 
0288 static DEFINE_SIMPLE_DEV_PM_OPS(st_wdog_pm_ops,
0289                 st_wdog_suspend, st_wdog_resume);
0290 
0291 static struct platform_driver st_wdog_driver = {
0292     .driver = {
0293         .name = "st-lpc-wdt",
0294         .pm = pm_sleep_ptr(&st_wdog_pm_ops),
0295         .of_match_table = st_wdog_match,
0296     },
0297     .probe = st_wdog_probe,
0298     .remove = st_wdog_remove,
0299 };
0300 module_platform_driver(st_wdog_driver);
0301 
0302 MODULE_AUTHOR("David Paris <david.paris@st.com>");
0303 MODULE_DESCRIPTION("ST LPC Watchdog Driver");
0304 MODULE_LICENSE("GPL");