Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright © 2014-2017 Broadcom
0004  */
0005 
0006 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0007 
0008 #include <linux/clk.h>
0009 #include <linux/device.h>
0010 #include <linux/err.h>
0011 #include <linux/init.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/io.h>
0014 #include <linux/irqreturn.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/pm.h>
0020 #include <linux/pm_wakeup.h>
0021 #include <linux/reboot.h>
0022 #include <linux/rtc.h>
0023 #include <linux/stat.h>
0024 #include <linux/suspend.h>
0025 
0026 struct brcmstb_waketmr {
0027     struct rtc_device *rtc;
0028     struct device *dev;
0029     void __iomem *base;
0030     int irq;
0031     struct notifier_block reboot_notifier;
0032     struct clk *clk;
0033     u32 rate;
0034 };
0035 
0036 #define BRCMSTB_WKTMR_EVENT     0x00
0037 #define BRCMSTB_WKTMR_COUNTER       0x04
0038 #define BRCMSTB_WKTMR_ALARM     0x08
0039 #define BRCMSTB_WKTMR_PRESCALER     0x0C
0040 #define BRCMSTB_WKTMR_PRESCALER_VAL 0x10
0041 
0042 #define BRCMSTB_WKTMR_DEFAULT_FREQ  27000000
0043 
0044 static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer)
0045 {
0046     writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT);
0047     (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
0048 }
0049 
0050 static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
0051                       unsigned int secs)
0052 {
0053     brcmstb_waketmr_clear_alarm(timer);
0054 
0055     /* Make sure we are actually counting in seconds */
0056     writel_relaxed(timer->rate, timer->base + BRCMSTB_WKTMR_PRESCALER);
0057 
0058     writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM);
0059 }
0060 
0061 static irqreturn_t brcmstb_waketmr_irq(int irq, void *data)
0062 {
0063     struct brcmstb_waketmr *timer = data;
0064 
0065     pm_wakeup_event(timer->dev, 0);
0066 
0067     return IRQ_HANDLED;
0068 }
0069 
0070 struct wktmr_time {
0071     u32 sec;
0072     u32 pre;
0073 };
0074 
0075 static void wktmr_read(struct brcmstb_waketmr *timer,
0076                struct wktmr_time *t)
0077 {
0078     u32 tmp;
0079 
0080     do {
0081         t->sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
0082         tmp = readl_relaxed(timer->base + BRCMSTB_WKTMR_PRESCALER_VAL);
0083     } while (tmp >= timer->rate);
0084 
0085     t->pre = timer->rate - tmp;
0086 }
0087 
0088 static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer)
0089 {
0090     struct device *dev = timer->dev;
0091     int ret = 0;
0092 
0093     if (device_may_wakeup(dev)) {
0094         ret = enable_irq_wake(timer->irq);
0095         if (ret) {
0096             dev_err(dev, "failed to enable wake-up interrupt\n");
0097             return ret;
0098         }
0099     }
0100 
0101     return ret;
0102 }
0103 
0104 /* If enabled as a wakeup-source, arm the timer when powering off */
0105 static int brcmstb_waketmr_reboot(struct notifier_block *nb,
0106         unsigned long action, void *data)
0107 {
0108     struct brcmstb_waketmr *timer;
0109 
0110     timer = container_of(nb, struct brcmstb_waketmr, reboot_notifier);
0111 
0112     /* Set timer for cold boot */
0113     if (action == SYS_POWER_OFF)
0114         brcmstb_waketmr_prepare_suspend(timer);
0115 
0116     return NOTIFY_DONE;
0117 }
0118 
0119 static int brcmstb_waketmr_gettime(struct device *dev,
0120                    struct rtc_time *tm)
0121 {
0122     struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
0123     struct wktmr_time now;
0124 
0125     wktmr_read(timer, &now);
0126 
0127     rtc_time64_to_tm(now.sec, tm);
0128 
0129     return 0;
0130 }
0131 
0132 static int brcmstb_waketmr_settime(struct device *dev,
0133                    struct rtc_time *tm)
0134 {
0135     struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
0136     time64_t sec;
0137 
0138     sec = rtc_tm_to_time64(tm);
0139 
0140     writel_relaxed(sec, timer->base + BRCMSTB_WKTMR_COUNTER);
0141 
0142     return 0;
0143 }
0144 
0145 static int brcmstb_waketmr_getalarm(struct device *dev,
0146                     struct rtc_wkalrm *alarm)
0147 {
0148     struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
0149     time64_t sec;
0150     u32 reg;
0151 
0152     sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM);
0153     if (sec != 0) {
0154         /* Alarm is enabled */
0155         alarm->enabled = 1;
0156         rtc_time64_to_tm(sec, &alarm->time);
0157     }
0158 
0159     reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
0160     alarm->pending = !!(reg & 1);
0161 
0162     return 0;
0163 }
0164 
0165 static int brcmstb_waketmr_setalarm(struct device *dev,
0166                      struct rtc_wkalrm *alarm)
0167 {
0168     struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
0169     time64_t sec;
0170 
0171     if (alarm->enabled)
0172         sec = rtc_tm_to_time64(&alarm->time);
0173     else
0174         sec = 0;
0175 
0176     brcmstb_waketmr_set_alarm(timer, sec);
0177 
0178     return 0;
0179 }
0180 
0181 /*
0182  * Does not do much but keep the RTC class happy. We always support
0183  * alarms.
0184  */
0185 static int brcmstb_waketmr_alarm_enable(struct device *dev,
0186                     unsigned int enabled)
0187 {
0188     return 0;
0189 }
0190 
0191 static const struct rtc_class_ops brcmstb_waketmr_ops = {
0192     .read_time  = brcmstb_waketmr_gettime,
0193     .set_time   = brcmstb_waketmr_settime,
0194     .read_alarm = brcmstb_waketmr_getalarm,
0195     .set_alarm  = brcmstb_waketmr_setalarm,
0196     .alarm_irq_enable = brcmstb_waketmr_alarm_enable,
0197 };
0198 
0199 static int brcmstb_waketmr_probe(struct platform_device *pdev)
0200 {
0201     struct device *dev = &pdev->dev;
0202     struct brcmstb_waketmr *timer;
0203     int ret;
0204 
0205     timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
0206     if (!timer)
0207         return -ENOMEM;
0208 
0209     platform_set_drvdata(pdev, timer);
0210     timer->dev = dev;
0211 
0212     timer->base = devm_platform_ioremap_resource(pdev, 0);
0213     if (IS_ERR(timer->base))
0214         return PTR_ERR(timer->base);
0215 
0216     timer->rtc = devm_rtc_allocate_device(dev);
0217     if (IS_ERR(timer->rtc))
0218         return PTR_ERR(timer->rtc);
0219 
0220     /*
0221      * Set wakeup capability before requesting wakeup interrupt, so we can
0222      * process boot-time "wakeups" (e.g., from S5 soft-off)
0223      */
0224     device_set_wakeup_capable(dev, true);
0225     device_wakeup_enable(dev);
0226 
0227     timer->irq = platform_get_irq(pdev, 0);
0228     if (timer->irq < 0)
0229         return -ENODEV;
0230 
0231     timer->clk = devm_clk_get(dev, NULL);
0232     if (!IS_ERR(timer->clk)) {
0233         ret = clk_prepare_enable(timer->clk);
0234         if (ret)
0235             return ret;
0236         timer->rate = clk_get_rate(timer->clk);
0237         if (!timer->rate)
0238             timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
0239     } else {
0240         timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
0241         timer->clk = NULL;
0242     }
0243 
0244     ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0,
0245                    "brcmstb-waketimer", timer);
0246     if (ret < 0)
0247         goto err_clk;
0248 
0249     timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot;
0250     register_reboot_notifier(&timer->reboot_notifier);
0251 
0252     timer->rtc->ops = &brcmstb_waketmr_ops;
0253     timer->rtc->range_max = U32_MAX;
0254 
0255     ret = devm_rtc_register_device(timer->rtc);
0256     if (ret)
0257         goto err_notifier;
0258 
0259     dev_info(dev, "registered, with irq %d\n", timer->irq);
0260 
0261     return 0;
0262 
0263 err_notifier:
0264     unregister_reboot_notifier(&timer->reboot_notifier);
0265 
0266 err_clk:
0267     clk_disable_unprepare(timer->clk);
0268 
0269     return ret;
0270 }
0271 
0272 static int brcmstb_waketmr_remove(struct platform_device *pdev)
0273 {
0274     struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev);
0275 
0276     unregister_reboot_notifier(&timer->reboot_notifier);
0277     clk_disable_unprepare(timer->clk);
0278 
0279     return 0;
0280 }
0281 
0282 #ifdef CONFIG_PM_SLEEP
0283 static int brcmstb_waketmr_suspend(struct device *dev)
0284 {
0285     struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
0286 
0287     return brcmstb_waketmr_prepare_suspend(timer);
0288 }
0289 
0290 static int brcmstb_waketmr_resume(struct device *dev)
0291 {
0292     struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
0293     int ret;
0294 
0295     if (!device_may_wakeup(dev))
0296         return 0;
0297 
0298     ret = disable_irq_wake(timer->irq);
0299 
0300     brcmstb_waketmr_clear_alarm(timer);
0301 
0302     return ret;
0303 }
0304 #endif /* CONFIG_PM_SLEEP */
0305 
0306 static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops,
0307              brcmstb_waketmr_suspend, brcmstb_waketmr_resume);
0308 
0309 static const __maybe_unused struct of_device_id brcmstb_waketmr_of_match[] = {
0310     { .compatible = "brcm,brcmstb-waketimer" },
0311     { /* sentinel */ },
0312 };
0313 
0314 static struct platform_driver brcmstb_waketmr_driver = {
0315     .probe          = brcmstb_waketmr_probe,
0316     .remove         = brcmstb_waketmr_remove,
0317     .driver = {
0318         .name       = "brcmstb-waketimer",
0319         .pm     = &brcmstb_waketmr_pm_ops,
0320         .of_match_table = of_match_ptr(brcmstb_waketmr_of_match),
0321     }
0322 };
0323 module_platform_driver(brcmstb_waketmr_driver);
0324 
0325 MODULE_LICENSE("GPL v2");
0326 MODULE_AUTHOR("Brian Norris");
0327 MODULE_AUTHOR("Markus Mayer");
0328 MODULE_DESCRIPTION("Wake-up timer driver for STB chips");