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 unsigned int wake_irq; 31 unsigned int alarm_irq; 32 struct notifier_block reboot_notifier; 33 struct clk *clk; 34 u32 rate; 35 unsigned long rtc_alarm; 36 bool alarm_en; 37 }; 38 39 #define BRCMSTB_WKTMR_EVENT 0x00 40 #define WKTMR_ALARM_EVENT BIT(0) 41 #define BRCMSTB_WKTMR_COUNTER 0x04 42 #define BRCMSTB_WKTMR_ALARM 0x08 43 #define BRCMSTB_WKTMR_PRESCALER 0x0C 44 #define BRCMSTB_WKTMR_PRESCALER_VAL 0x10 45 46 #define BRCMSTB_WKTMR_DEFAULT_FREQ 27000000 47 48 static inline bool brcmstb_waketmr_is_pending(struct brcmstb_waketmr *timer) 49 { 50 u32 reg; 51 52 reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); 53 return !!(reg & WKTMR_ALARM_EVENT); 54 } 55 56 static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer) 57 { 58 u32 reg; 59 60 if (timer->alarm_en && timer->alarm_irq) 61 disable_irq(timer->alarm_irq); 62 timer->alarm_en = false; 63 reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER); 64 writel_relaxed(reg - 1, timer->base + BRCMSTB_WKTMR_ALARM); 65 writel_relaxed(WKTMR_ALARM_EVENT, timer->base + BRCMSTB_WKTMR_EVENT); 66 (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); 67 } 68 69 static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer, 70 unsigned int secs) 71 { 72 unsigned int now; 73 74 brcmstb_waketmr_clear_alarm(timer); 75 76 /* Make sure we are actually counting in seconds */ 77 writel_relaxed(timer->rate, timer->base + BRCMSTB_WKTMR_PRESCALER); 78 79 writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM); 80 now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER); 81 82 while ((int)(secs - now) <= 0 && 83 !brcmstb_waketmr_is_pending(timer)) { 84 secs = now + 1; 85 writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM); 86 now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER); 87 } 88 } 89 90 static irqreturn_t brcmstb_waketmr_irq(int irq, void *data) 91 { 92 struct brcmstb_waketmr *timer = data; 93 94 if (!timer->alarm_irq) 95 pm_wakeup_event(timer->dev, 0); 96 return IRQ_HANDLED; 97 } 98 99 static irqreturn_t brcmstb_alarm_irq(int irq, void *data) 100 { 101 struct brcmstb_waketmr *timer = data; 102 103 /* Ignore spurious interrupts */ 104 if (!brcmstb_waketmr_is_pending(timer)) 105 return IRQ_HANDLED; 106 107 if (timer->alarm_en) { 108 if (!device_may_wakeup(timer->dev)) 109 writel_relaxed(WKTMR_ALARM_EVENT, 110 timer->base + BRCMSTB_WKTMR_EVENT); 111 rtc_update_irq(timer->rtc, 1, RTC_IRQF | RTC_AF); 112 } 113 114 return IRQ_HANDLED; 115 } 116 117 struct wktmr_time { 118 u32 sec; 119 u32 pre; 120 }; 121 122 static void wktmr_read(struct brcmstb_waketmr *timer, 123 struct wktmr_time *t) 124 { 125 u32 tmp; 126 127 do { 128 t->sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER); 129 tmp = readl_relaxed(timer->base + BRCMSTB_WKTMR_PRESCALER_VAL); 130 } while (tmp >= timer->rate); 131 132 t->pre = timer->rate - tmp; 133 } 134 135 static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer) 136 { 137 struct device *dev = timer->dev; 138 int ret; 139 140 if (device_may_wakeup(dev)) { 141 ret = enable_irq_wake(timer->wake_irq); 142 if (ret) { 143 dev_err(dev, "failed to enable wake-up interrupt\n"); 144 return ret; 145 } 146 if (timer->alarm_en && timer->alarm_irq) { 147 ret = enable_irq_wake(timer->alarm_irq); 148 if (ret) { 149 dev_err(dev, "failed to enable rtc interrupt\n"); 150 disable_irq_wake(timer->wake_irq); 151 return ret; 152 } 153 } 154 } 155 156 return 0; 157 } 158 159 /* If enabled as a wakeup-source, arm the timer when powering off */ 160 static int brcmstb_waketmr_reboot(struct notifier_block *nb, 161 unsigned long action, void *data) 162 { 163 struct brcmstb_waketmr *timer; 164 165 timer = container_of(nb, struct brcmstb_waketmr, reboot_notifier); 166 167 /* Set timer for cold boot */ 168 if (action == SYS_POWER_OFF) 169 brcmstb_waketmr_prepare_suspend(timer); 170 171 return NOTIFY_DONE; 172 } 173 174 static int brcmstb_waketmr_gettime(struct device *dev, 175 struct rtc_time *tm) 176 { 177 struct brcmstb_waketmr *timer = dev_get_drvdata(dev); 178 struct wktmr_time now; 179 180 wktmr_read(timer, &now); 181 182 rtc_time64_to_tm(now.sec, tm); 183 184 return 0; 185 } 186 187 static int brcmstb_waketmr_settime(struct device *dev, 188 struct rtc_time *tm) 189 { 190 struct brcmstb_waketmr *timer = dev_get_drvdata(dev); 191 time64_t sec; 192 193 sec = rtc_tm_to_time64(tm); 194 195 writel_relaxed(sec, timer->base + BRCMSTB_WKTMR_COUNTER); 196 197 return 0; 198 } 199 200 static int brcmstb_waketmr_getalarm(struct device *dev, 201 struct rtc_wkalrm *alarm) 202 { 203 struct brcmstb_waketmr *timer = dev_get_drvdata(dev); 204 205 alarm->enabled = timer->alarm_en; 206 rtc_time64_to_tm(timer->rtc_alarm, &alarm->time); 207 208 alarm->pending = brcmstb_waketmr_is_pending(timer); 209 210 return 0; 211 } 212 213 static int brcmstb_waketmr_alarm_enable(struct device *dev, 214 unsigned int enabled) 215 { 216 struct brcmstb_waketmr *timer = dev_get_drvdata(dev); 217 218 if (enabled && !timer->alarm_en) { 219 if ((int)(readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER) - 220 readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM)) >= 0 && 221 !brcmstb_waketmr_is_pending(timer)) 222 return -EINVAL; 223 timer->alarm_en = true; 224 if (timer->alarm_irq) 225 enable_irq(timer->alarm_irq); 226 } else if (!enabled && timer->alarm_en) { 227 if (timer->alarm_irq) 228 disable_irq(timer->alarm_irq); 229 timer->alarm_en = false; 230 } 231 232 return 0; 233 } 234 235 static int brcmstb_waketmr_setalarm(struct device *dev, 236 struct rtc_wkalrm *alarm) 237 { 238 struct brcmstb_waketmr *timer = dev_get_drvdata(dev); 239 240 timer->rtc_alarm = rtc_tm_to_time64(&alarm->time); 241 242 brcmstb_waketmr_set_alarm(timer, timer->rtc_alarm); 243 244 return brcmstb_waketmr_alarm_enable(dev, alarm->enabled); 245 } 246 247 static const struct rtc_class_ops brcmstb_waketmr_ops = { 248 .read_time = brcmstb_waketmr_gettime, 249 .set_time = brcmstb_waketmr_settime, 250 .read_alarm = brcmstb_waketmr_getalarm, 251 .set_alarm = brcmstb_waketmr_setalarm, 252 .alarm_irq_enable = brcmstb_waketmr_alarm_enable, 253 }; 254 255 static int brcmstb_waketmr_probe(struct platform_device *pdev) 256 { 257 struct device *dev = &pdev->dev; 258 struct brcmstb_waketmr *timer; 259 int ret; 260 261 timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL); 262 if (!timer) 263 return -ENOMEM; 264 265 platform_set_drvdata(pdev, timer); 266 timer->dev = dev; 267 268 timer->base = devm_platform_ioremap_resource(pdev, 0); 269 if (IS_ERR(timer->base)) 270 return PTR_ERR(timer->base); 271 272 timer->rtc = devm_rtc_allocate_device(dev); 273 if (IS_ERR(timer->rtc)) 274 return PTR_ERR(timer->rtc); 275 276 /* 277 * Set wakeup capability before requesting wakeup interrupt, so we can 278 * process boot-time "wakeups" (e.g., from S5 soft-off) 279 */ 280 device_init_wakeup(dev, true); 281 282 ret = platform_get_irq(pdev, 0); 283 if (ret < 0) 284 return -ENODEV; 285 timer->wake_irq = (unsigned int)ret; 286 287 timer->clk = devm_clk_get(dev, NULL); 288 if (!IS_ERR(timer->clk)) { 289 ret = clk_prepare_enable(timer->clk); 290 if (ret) 291 return ret; 292 timer->rate = clk_get_rate(timer->clk); 293 if (!timer->rate) 294 timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ; 295 } else { 296 timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ; 297 timer->clk = NULL; 298 } 299 300 ret = devm_request_irq(dev, timer->wake_irq, brcmstb_waketmr_irq, 0, 301 "brcmstb-waketimer", timer); 302 if (ret < 0) 303 goto err_clk; 304 305 brcmstb_waketmr_clear_alarm(timer); 306 307 /* Attempt to initialize non-wake irq */ 308 ret = platform_get_irq(pdev, 1); 309 if (ret > 0) { 310 timer->alarm_irq = (unsigned int)ret; 311 ret = devm_request_irq(dev, timer->alarm_irq, brcmstb_alarm_irq, 312 IRQF_NO_AUTOEN, "brcmstb-waketimer-rtc", 313 timer); 314 if (ret < 0) 315 timer->alarm_irq = 0; 316 } 317 318 timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot; 319 register_reboot_notifier(&timer->reboot_notifier); 320 321 timer->rtc->ops = &brcmstb_waketmr_ops; 322 timer->rtc->range_max = U32_MAX; 323 324 ret = devm_rtc_register_device(timer->rtc); 325 if (ret) 326 goto err_notifier; 327 328 return 0; 329 330 err_notifier: 331 unregister_reboot_notifier(&timer->reboot_notifier); 332 333 err_clk: 334 clk_disable_unprepare(timer->clk); 335 336 return ret; 337 } 338 339 static int brcmstb_waketmr_remove(struct platform_device *pdev) 340 { 341 struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev); 342 343 unregister_reboot_notifier(&timer->reboot_notifier); 344 clk_disable_unprepare(timer->clk); 345 346 return 0; 347 } 348 349 #ifdef CONFIG_PM_SLEEP 350 static int brcmstb_waketmr_suspend(struct device *dev) 351 { 352 struct brcmstb_waketmr *timer = dev_get_drvdata(dev); 353 354 return brcmstb_waketmr_prepare_suspend(timer); 355 } 356 357 static int brcmstb_waketmr_resume(struct device *dev) 358 { 359 struct brcmstb_waketmr *timer = dev_get_drvdata(dev); 360 int ret; 361 362 if (!device_may_wakeup(dev)) 363 return 0; 364 365 ret = disable_irq_wake(timer->wake_irq); 366 if (timer->alarm_en && timer->alarm_irq) 367 disable_irq_wake(timer->alarm_irq); 368 369 brcmstb_waketmr_clear_alarm(timer); 370 371 return ret; 372 } 373 #endif /* CONFIG_PM_SLEEP */ 374 375 static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops, 376 brcmstb_waketmr_suspend, brcmstb_waketmr_resume); 377 378 static const __maybe_unused struct of_device_id brcmstb_waketmr_of_match[] = { 379 { .compatible = "brcm,brcmstb-waketimer" }, 380 { /* sentinel */ }, 381 }; 382 383 static struct platform_driver brcmstb_waketmr_driver = { 384 .probe = brcmstb_waketmr_probe, 385 .remove = brcmstb_waketmr_remove, 386 .driver = { 387 .name = "brcmstb-waketimer", 388 .pm = &brcmstb_waketmr_pm_ops, 389 .of_match_table = of_match_ptr(brcmstb_waketmr_of_match), 390 } 391 }; 392 module_platform_driver(brcmstb_waketmr_driver); 393 394 MODULE_LICENSE("GPL v2"); 395 MODULE_AUTHOR("Brian Norris"); 396 MODULE_AUTHOR("Markus Mayer"); 397 MODULE_AUTHOR("Doug Berger"); 398 MODULE_DESCRIPTION("Wake-up timer driver for STB chips"); 399