root/drivers/rtc/rtc-brcmstb-waketimer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. brcmstb_waketmr_clear_alarm
  2. brcmstb_waketmr_set_alarm
  3. brcmstb_waketmr_irq
  4. wktmr_read
  5. brcmstb_waketmr_prepare_suspend
  6. brcmstb_waketmr_reboot
  7. brcmstb_waketmr_gettime
  8. brcmstb_waketmr_settime
  9. brcmstb_waketmr_getalarm
  10. brcmstb_waketmr_setalarm
  11. brcmstb_waketmr_alarm_enable
  12. brcmstb_waketmr_probe
  13. brcmstb_waketmr_remove
  14. brcmstb_waketmr_suspend
  15. brcmstb_waketmr_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright © 2014-2017 Broadcom
   4  */
   5 
   6 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
   7 
   8 #include <linux/clk.h>
   9 #include <linux/device.h>
  10 #include <linux/err.h>
  11 #include <linux/init.h>
  12 #include <linux/interrupt.h>
  13 #include <linux/io.h>
  14 #include <linux/irqreturn.h>
  15 #include <linux/kernel.h>
  16 #include <linux/module.h>
  17 #include <linux/of.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/pm.h>
  20 #include <linux/pm_wakeup.h>
  21 #include <linux/reboot.h>
  22 #include <linux/rtc.h>
  23 #include <linux/stat.h>
  24 #include <linux/suspend.h>
  25 
  26 struct brcmstb_waketmr {
  27         struct rtc_device *rtc;
  28         struct device *dev;
  29         void __iomem *base;
  30         int irq;
  31         struct notifier_block reboot_notifier;
  32         struct clk *clk;
  33         u32 rate;
  34 };
  35 
  36 #define BRCMSTB_WKTMR_EVENT             0x00
  37 #define BRCMSTB_WKTMR_COUNTER           0x04
  38 #define BRCMSTB_WKTMR_ALARM             0x08
  39 #define BRCMSTB_WKTMR_PRESCALER         0x0C
  40 #define BRCMSTB_WKTMR_PRESCALER_VAL     0x10
  41 
  42 #define BRCMSTB_WKTMR_DEFAULT_FREQ      27000000
  43 
  44 static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer)
  45 {
  46         writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT);
  47         (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
  48 }
  49 
  50 static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
  51                                       unsigned int secs)
  52 {
  53         brcmstb_waketmr_clear_alarm(timer);
  54 
  55         /* Make sure we are actually counting in seconds */
  56         writel_relaxed(timer->rate, timer->base + BRCMSTB_WKTMR_PRESCALER);
  57 
  58         writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM);
  59 }
  60 
  61 static irqreturn_t brcmstb_waketmr_irq(int irq, void *data)
  62 {
  63         struct brcmstb_waketmr *timer = data;
  64 
  65         pm_wakeup_event(timer->dev, 0);
  66 
  67         return IRQ_HANDLED;
  68 }
  69 
  70 struct wktmr_time {
  71         u32 sec;
  72         u32 pre;
  73 };
  74 
  75 static void wktmr_read(struct brcmstb_waketmr *timer,
  76                        struct wktmr_time *t)
  77 {
  78         u32 tmp;
  79 
  80         do {
  81                 t->sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
  82                 tmp = readl_relaxed(timer->base + BRCMSTB_WKTMR_PRESCALER_VAL);
  83         } while (tmp >= timer->rate);
  84 
  85         t->pre = timer->rate - tmp;
  86 }
  87 
  88 static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer)
  89 {
  90         struct device *dev = timer->dev;
  91         int ret = 0;
  92 
  93         if (device_may_wakeup(dev)) {
  94                 ret = enable_irq_wake(timer->irq);
  95                 if (ret) {
  96                         dev_err(dev, "failed to enable wake-up interrupt\n");
  97                         return ret;
  98                 }
  99         }
 100 
 101         return ret;
 102 }
 103 
 104 /* If enabled as a wakeup-source, arm the timer when powering off */
 105 static int brcmstb_waketmr_reboot(struct notifier_block *nb,
 106                 unsigned long action, void *data)
 107 {
 108         struct brcmstb_waketmr *timer;
 109 
 110         timer = container_of(nb, struct brcmstb_waketmr, reboot_notifier);
 111 
 112         /* Set timer for cold boot */
 113         if (action == SYS_POWER_OFF)
 114                 brcmstb_waketmr_prepare_suspend(timer);
 115 
 116         return NOTIFY_DONE;
 117 }
 118 
 119 static int brcmstb_waketmr_gettime(struct device *dev,
 120                                    struct rtc_time *tm)
 121 {
 122         struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
 123         struct wktmr_time now;
 124 
 125         wktmr_read(timer, &now);
 126 
 127         rtc_time64_to_tm(now.sec, tm);
 128 
 129         return 0;
 130 }
 131 
 132 static int brcmstb_waketmr_settime(struct device *dev,
 133                                    struct rtc_time *tm)
 134 {
 135         struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
 136         time64_t sec;
 137 
 138         sec = rtc_tm_to_time64(tm);
 139 
 140         writel_relaxed(sec, timer->base + BRCMSTB_WKTMR_COUNTER);
 141 
 142         return 0;
 143 }
 144 
 145 static int brcmstb_waketmr_getalarm(struct device *dev,
 146                                     struct rtc_wkalrm *alarm)
 147 {
 148         struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
 149         time64_t sec;
 150         u32 reg;
 151 
 152         sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM);
 153         if (sec != 0) {
 154                 /* Alarm is enabled */
 155                 alarm->enabled = 1;
 156                 rtc_time64_to_tm(sec, &alarm->time);
 157         }
 158 
 159         reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
 160         alarm->pending = !!(reg & 1);
 161 
 162         return 0;
 163 }
 164 
 165 static int brcmstb_waketmr_setalarm(struct device *dev,
 166                                      struct rtc_wkalrm *alarm)
 167 {
 168         struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
 169         time64_t sec;
 170 
 171         if (alarm->enabled)
 172                 sec = rtc_tm_to_time64(&alarm->time);
 173         else
 174                 sec = 0;
 175 
 176         brcmstb_waketmr_set_alarm(timer, sec);
 177 
 178         return 0;
 179 }
 180 
 181 /*
 182  * Does not do much but keep the RTC class happy. We always support
 183  * alarms.
 184  */
 185 static int brcmstb_waketmr_alarm_enable(struct device *dev,
 186                                         unsigned int enabled)
 187 {
 188         return 0;
 189 }
 190 
 191 static const struct rtc_class_ops brcmstb_waketmr_ops = {
 192         .read_time      = brcmstb_waketmr_gettime,
 193         .set_time       = brcmstb_waketmr_settime,
 194         .read_alarm     = brcmstb_waketmr_getalarm,
 195         .set_alarm      = brcmstb_waketmr_setalarm,
 196         .alarm_irq_enable = brcmstb_waketmr_alarm_enable,
 197 };
 198 
 199 static int brcmstb_waketmr_probe(struct platform_device *pdev)
 200 {
 201         struct device *dev = &pdev->dev;
 202         struct brcmstb_waketmr *timer;
 203         struct resource *res;
 204         int ret;
 205 
 206         timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
 207         if (!timer)
 208                 return -ENOMEM;
 209 
 210         platform_set_drvdata(pdev, timer);
 211         timer->dev = dev;
 212 
 213         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 214         timer->base = devm_ioremap_resource(dev, res);
 215         if (IS_ERR(timer->base))
 216                 return PTR_ERR(timer->base);
 217 
 218         timer->rtc = devm_rtc_allocate_device(dev);
 219         if (IS_ERR(timer->rtc))
 220                 return PTR_ERR(timer->rtc);
 221 
 222         /*
 223          * Set wakeup capability before requesting wakeup interrupt, so we can
 224          * process boot-time "wakeups" (e.g., from S5 soft-off)
 225          */
 226         device_set_wakeup_capable(dev, true);
 227         device_wakeup_enable(dev);
 228 
 229         timer->irq = platform_get_irq(pdev, 0);
 230         if (timer->irq < 0)
 231                 return -ENODEV;
 232 
 233         timer->clk = devm_clk_get(dev, NULL);
 234         if (!IS_ERR(timer->clk)) {
 235                 ret = clk_prepare_enable(timer->clk);
 236                 if (ret)
 237                         return ret;
 238                 timer->rate = clk_get_rate(timer->clk);
 239                 if (!timer->rate)
 240                         timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
 241         } else {
 242                 timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
 243                 timer->clk = NULL;
 244         }
 245 
 246         ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0,
 247                                "brcmstb-waketimer", timer);
 248         if (ret < 0)
 249                 goto err_clk;
 250 
 251         timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot;
 252         register_reboot_notifier(&timer->reboot_notifier);
 253 
 254         timer->rtc->ops = &brcmstb_waketmr_ops;
 255         timer->rtc->range_max = U32_MAX;
 256 
 257         ret = rtc_register_device(timer->rtc);
 258         if (ret)
 259                 goto err_notifier;
 260 
 261         dev_info(dev, "registered, with irq %d\n", timer->irq);
 262 
 263         return 0;
 264 
 265 err_notifier:
 266         unregister_reboot_notifier(&timer->reboot_notifier);
 267 
 268 err_clk:
 269         if (timer->clk)
 270                 clk_disable_unprepare(timer->clk);
 271 
 272         return ret;
 273 }
 274 
 275 static int brcmstb_waketmr_remove(struct platform_device *pdev)
 276 {
 277         struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev);
 278 
 279         unregister_reboot_notifier(&timer->reboot_notifier);
 280         clk_disable_unprepare(timer->clk);
 281 
 282         return 0;
 283 }
 284 
 285 #ifdef CONFIG_PM_SLEEP
 286 static int brcmstb_waketmr_suspend(struct device *dev)
 287 {
 288         struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
 289 
 290         return brcmstb_waketmr_prepare_suspend(timer);
 291 }
 292 
 293 static int brcmstb_waketmr_resume(struct device *dev)
 294 {
 295         struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
 296         int ret;
 297 
 298         if (!device_may_wakeup(dev))
 299                 return 0;
 300 
 301         ret = disable_irq_wake(timer->irq);
 302 
 303         brcmstb_waketmr_clear_alarm(timer);
 304 
 305         return ret;
 306 }
 307 #endif /* CONFIG_PM_SLEEP */
 308 
 309 static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops,
 310                          brcmstb_waketmr_suspend, brcmstb_waketmr_resume);
 311 
 312 static const struct of_device_id brcmstb_waketmr_of_match[] = {
 313         { .compatible = "brcm,brcmstb-waketimer" },
 314         { /* sentinel */ },
 315 };
 316 
 317 static struct platform_driver brcmstb_waketmr_driver = {
 318         .probe                  = brcmstb_waketmr_probe,
 319         .remove                 = brcmstb_waketmr_remove,
 320         .driver = {
 321                 .name           = "brcmstb-waketimer",
 322                 .pm             = &brcmstb_waketmr_pm_ops,
 323                 .of_match_table = of_match_ptr(brcmstb_waketmr_of_match),
 324         }
 325 };
 326 module_platform_driver(brcmstb_waketmr_driver);
 327 
 328 MODULE_LICENSE("GPL v2");
 329 MODULE_AUTHOR("Brian Norris");
 330 MODULE_AUTHOR("Markus Mayer");
 331 MODULE_DESCRIPTION("Wake-up timer driver for STB chips");

/* [<][>][^][v][top][bottom][index][help] */