Lines Matching +full:sun6i +full:- +full:a31 +full:- +full:rtc

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * An RTC driver for Allwinner A31/A23
5 * Copyright (c) 2014, Chen-Yu Tsai <wens@csie.org>
7 * based on rtc-sunxi.c
9 * An RTC driver for Allwinner A10/A20
15 #include <linux/clk-provider.h>
28 #include <linux/rtc.h>
45 /* RTC */
107 * The year range is 1970 - 2033. This range is selected to match Allwinner's
111 #define SUN6I_YEAR_OFF (SUN6I_YEAR_MIN - 1900)
116 * - number of GPIO pins that can be configured to hold a certain level
117 * - crypto-key related registers (H5, H6)
118 * - boot process related (super standby, secondary processor entry address)
120 * - SYS power domain controls (R40)
121 * - DCXO controls (H6)
122 * - RC oscillator calibration (H6)
137 struct rtc_device *rtc; member
156 struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw); in sun6i_rtc_osc_recalc_rate() local
159 val = readl(rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_osc_recalc_rate()
163 if (rtc->data->fixed_prescaler) in sun6i_rtc_osc_recalc_rate()
164 parent_rate /= rtc->data->fixed_prescaler; in sun6i_rtc_osc_recalc_rate()
166 if (rtc->data->has_prescaler) { in sun6i_rtc_osc_recalc_rate()
167 val = readl(rtc->base + SUN6I_LOSC_CLK_PRESCAL); in sun6i_rtc_osc_recalc_rate()
176 struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw); in sun6i_rtc_osc_get_parent() local
178 return readl(rtc->base + SUN6I_LOSC_CTRL) & SUN6I_LOSC_CTRL_EXT_OSC; in sun6i_rtc_osc_get_parent()
183 struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw); in sun6i_rtc_osc_set_parent() local
188 return -EINVAL; in sun6i_rtc_osc_set_parent()
190 spin_lock_irqsave(&rtc->lock, flags); in sun6i_rtc_osc_set_parent()
191 val = readl(rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_osc_set_parent()
195 if (rtc->data->has_losc_en) { in sun6i_rtc_osc_set_parent()
199 writel(val, rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_osc_set_parent()
200 spin_unlock_irqrestore(&rtc->lock, flags); in sun6i_rtc_osc_set_parent()
216 struct sun6i_rtc_dev *rtc; in sun6i_rtc_clk_init() local
221 const char *iosc_name = "rtc-int-osc"; in sun6i_rtc_clk_init()
222 const char *clkout_name = "osc32k-out"; in sun6i_rtc_clk_init()
226 rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); in sun6i_rtc_clk_init()
227 if (!rtc) in sun6i_rtc_clk_init()
230 rtc->data = data; in sun6i_rtc_clk_init()
233 kfree(rtc); in sun6i_rtc_clk_init()
237 spin_lock_init(&rtc->lock); in sun6i_rtc_clk_init()
239 rtc->base = of_io_request_and_map(node, 0, of_node_full_name(node)); in sun6i_rtc_clk_init()
240 if (IS_ERR(rtc->base)) { in sun6i_rtc_clk_init()
241 pr_crit("Can't map RTC registers"); in sun6i_rtc_clk_init()
246 if (rtc->data->has_auto_swt) { in sun6i_rtc_clk_init()
247 /* Bypass auto-switch to int osc, on ext losc failure */ in sun6i_rtc_clk_init()
249 writel(reg, rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_clk_init()
255 if (rtc->data->has_losc_en) in sun6i_rtc_clk_init()
258 writel(reg, rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_clk_init()
261 sun6i_rtc = rtc; in sun6i_rtc_clk_init()
264 if (rtc->data->export_iosc) in sun6i_rtc_clk_init()
265 of_property_read_string_index(node, "clock-output-names", 2, in sun6i_rtc_clk_init()
268 rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL, in sun6i_rtc_clk_init()
271 rtc->data->rc_osc_rate, in sun6i_rtc_clk_init()
273 if (IS_ERR(rtc->int_osc)) { in sun6i_rtc_clk_init()
278 parents[0] = clk_hw_get_name(rtc->int_osc); in sun6i_rtc_clk_init()
282 rtc->hw.init = &init; in sun6i_rtc_clk_init()
287 of_property_read_string_index(node, "clock-output-names", 0, in sun6i_rtc_clk_init()
290 rtc->losc = clk_register(NULL, &rtc->hw); in sun6i_rtc_clk_init()
291 if (IS_ERR(rtc->losc)) { in sun6i_rtc_clk_init()
296 of_property_read_string_index(node, "clock-output-names", 1, in sun6i_rtc_clk_init()
298 rtc->ext_losc = clk_register_gate(NULL, clkout_name, init.name, in sun6i_rtc_clk_init()
299 0, rtc->base + SUN6I_LOSC_OUT_GATING, in sun6i_rtc_clk_init()
301 &rtc->lock); in sun6i_rtc_clk_init()
302 if (IS_ERR(rtc->ext_losc)) { in sun6i_rtc_clk_init()
307 clk_data->num = 2; in sun6i_rtc_clk_init()
308 clk_data->hws[0] = &rtc->hw; in sun6i_rtc_clk_init()
309 clk_data->hws[1] = __clk_get_hw(rtc->ext_losc); in sun6i_rtc_clk_init()
310 if (rtc->data->export_iosc) { in sun6i_rtc_clk_init()
311 clk_data->hws[2] = rtc->int_osc; in sun6i_rtc_clk_init()
312 clk_data->num = 3; in sun6i_rtc_clk_init()
318 clk_hw_unregister_fixed_rate(rtc->int_osc); in sun6i_rtc_clk_init()
332 CLK_OF_DECLARE_DRIVER(sun6i_a31_rtc_clk, "allwinner,sun6i-a31-rtc",
345 CLK_OF_DECLARE_DRIVER(sun8i_a23_rtc_clk, "allwinner,sun8i-a23-rtc",
360 CLK_OF_DECLARE_DRIVER(sun8i_h3_rtc_clk, "allwinner,sun8i-h3-rtc",
363 CLK_OF_DECLARE_DRIVER(sun50i_h5_rtc_clk, "allwinner,sun50i-h5-rtc",
380 CLK_OF_DECLARE_DRIVER(sun50i_h6_rtc_clk, "allwinner,sun50i-h6-rtc",
384 * The R40 user manual is self-conflicting on whether the prescaler is
386 * is also a configurable divider in the RTC block.
396 CLK_OF_DECLARE_DRIVER(sun8i_r40_rtc_clk, "allwinner,sun8i-r40-rtc",
408 CLK_OF_DECLARE_DRIVER(sun8i_v3_rtc_clk, "allwinner,sun8i-v3-rtc",
417 spin_lock(&chip->lock); in sun6i_rtc_alarmirq()
418 val = readl(chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_alarmirq()
422 writel(val, chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_alarmirq()
424 rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); in sun6i_rtc_alarmirq()
428 spin_unlock(&chip->lock); in sun6i_rtc_alarmirq()
446 chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_setaie()
449 spin_lock_irqsave(&chip->lock, flags); in sun6i_rtc_setaie()
450 writel(alrm_val, chip->base + SUN6I_ALRM_EN); in sun6i_rtc_setaie()
451 writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_setaie()
452 writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG); in sun6i_rtc_setaie()
453 spin_unlock_irqrestore(&chip->lock, flags); in sun6i_rtc_setaie()
465 date = readl(chip->base + SUN6I_RTC_YMD); in sun6i_rtc_gettime()
466 time = readl(chip->base + SUN6I_RTC_HMS); in sun6i_rtc_gettime()
467 } while ((date != readl(chip->base + SUN6I_RTC_YMD)) || in sun6i_rtc_gettime()
468 (time != readl(chip->base + SUN6I_RTC_HMS))); in sun6i_rtc_gettime()
470 rtc_tm->tm_sec = SUN6I_TIME_GET_SEC_VALUE(time); in sun6i_rtc_gettime()
471 rtc_tm->tm_min = SUN6I_TIME_GET_MIN_VALUE(time); in sun6i_rtc_gettime()
472 rtc_tm->tm_hour = SUN6I_TIME_GET_HOUR_VALUE(time); in sun6i_rtc_gettime()
474 rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date); in sun6i_rtc_gettime()
475 rtc_tm->tm_mon = SUN6I_DATE_GET_MON_VALUE(date); in sun6i_rtc_gettime()
476 rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date); in sun6i_rtc_gettime()
478 rtc_tm->tm_mon -= 1; in sun6i_rtc_gettime()
481 * switch from (data_year->min)-relative offset to in sun6i_rtc_gettime()
482 * a (1900)-relative one in sun6i_rtc_gettime()
484 rtc_tm->tm_year += SUN6I_YEAR_OFF; in sun6i_rtc_gettime()
496 spin_lock_irqsave(&chip->lock, flags); in sun6i_rtc_getalarm()
497 alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_getalarm()
498 alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_getalarm()
499 spin_unlock_irqrestore(&chip->lock, flags); in sun6i_rtc_getalarm()
501 wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN); in sun6i_rtc_getalarm()
502 wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN); in sun6i_rtc_getalarm()
503 rtc_time64_to_tm(chip->alarm, &wkalrm->time); in sun6i_rtc_getalarm()
511 struct rtc_time *alrm_tm = &wkalrm->time; in sun6i_rtc_setalarm()
519 return -EINVAL; in sun6i_rtc_setalarm()
526 return -EINVAL; in sun6i_rtc_setalarm()
529 if ((time_set - time_now) > U32_MAX) { in sun6i_rtc_setalarm()
531 return -EINVAL; in sun6i_rtc_setalarm()
535 writel(0, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_setalarm()
538 writel(time_set - time_now, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_setalarm()
539 chip->alarm = time_set; in sun6i_rtc_setalarm()
541 sun6i_rtc_setaie(wkalrm->enabled, chip); in sun6i_rtc_setalarm()
553 reg = readl(chip->base + offset); in sun6i_rtc_wait()
561 return -ETIMEDOUT; in sun6i_rtc_wait()
570 rtc_tm->tm_year -= SUN6I_YEAR_OFF; in sun6i_rtc_settime()
571 rtc_tm->tm_mon += 1; in sun6i_rtc_settime()
573 date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | in sun6i_rtc_settime()
574 SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon) | in sun6i_rtc_settime()
575 SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year); in sun6i_rtc_settime()
577 if (is_leap_year(rtc_tm->tm_year + SUN6I_YEAR_MIN)) in sun6i_rtc_settime()
580 time = SUN6I_TIME_SET_SEC_VALUE(rtc_tm->tm_sec) | in sun6i_rtc_settime()
581 SUN6I_TIME_SET_MIN_VALUE(rtc_tm->tm_min) | in sun6i_rtc_settime()
582 SUN6I_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour); in sun6i_rtc_settime()
587 dev_err(dev, "rtc is still busy.\n"); in sun6i_rtc_settime()
588 return -EBUSY; in sun6i_rtc_settime()
591 writel(time, chip->base + SUN6I_RTC_HMS); in sun6i_rtc_settime()
594 * After writing the RTC HH-MM-SS register, the in sun6i_rtc_settime()
601 dev_err(dev, "Failed to set rtc time.\n"); in sun6i_rtc_settime()
602 return -ETIMEDOUT; in sun6i_rtc_settime()
605 writel(date, chip->base + SUN6I_RTC_YMD); in sun6i_rtc_settime()
608 * After writing the RTC YY-MM-DD register, the in sun6i_rtc_settime()
615 dev_err(dev, "Failed to set rtc time.\n"); in sun6i_rtc_settime()
616 return -ETIMEDOUT; in sun6i_rtc_settime()
641 /* Enable IRQ wake on suspend, to wake up from RTC. */
647 enable_irq_wake(chip->irq); in sun6i_rtc_suspend()
658 disable_irq_wake(chip->irq); in sun6i_rtc_resume()
673 return -ENODEV; in sun6i_rtc_probe()
677 chip->irq = platform_get_irq(pdev, 0); in sun6i_rtc_probe()
678 if (chip->irq < 0) in sun6i_rtc_probe()
679 return chip->irq; in sun6i_rtc_probe()
681 ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq, in sun6i_rtc_probe()
682 0, dev_name(&pdev->dev), chip); in sun6i_rtc_probe()
684 dev_err(&pdev->dev, "Could not request IRQ\n"); in sun6i_rtc_probe()
689 writel(0, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_probe()
692 writel(0, chip->base + SUN6I_ALRM_EN); in sun6i_rtc_probe()
695 writel(0, chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_probe()
698 writel(0, chip->base + SUN6I_ALRM1_EN); in sun6i_rtc_probe()
701 writel(0, chip->base + SUN6I_ALRM1_IRQ_EN); in sun6i_rtc_probe()
705 chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_probe()
709 chip->base + SUN6I_ALRM1_IRQ_STA); in sun6i_rtc_probe()
712 writel(0, chip->base + SUN6I_ALARM_CONFIG); in sun6i_rtc_probe()
714 clk_prepare_enable(chip->losc); in sun6i_rtc_probe()
716 device_init_wakeup(&pdev->dev, 1); in sun6i_rtc_probe()
718 chip->rtc = devm_rtc_allocate_device(&pdev->dev); in sun6i_rtc_probe()
719 if (IS_ERR(chip->rtc)) in sun6i_rtc_probe()
720 return PTR_ERR(chip->rtc); in sun6i_rtc_probe()
722 chip->rtc->ops = &sun6i_rtc_ops; in sun6i_rtc_probe()
723 chip->rtc->range_max = 2019686399LL; /* 2033-12-31 23:59:59 */ in sun6i_rtc_probe()
725 ret = rtc_register_device(chip->rtc); in sun6i_rtc_probe()
729 dev_info(&pdev->dev, "RTC enabled\n"); in sun6i_rtc_probe()
735 * As far as RTC functionality goes, all models are the same. The
737 * registers available for non-volatile storage, but experiments show
741 { .compatible = "allwinner,sun6i-a31-rtc" },
742 { .compatible = "allwinner,sun8i-a23-rtc" },
743 { .compatible = "allwinner,sun8i-h3-rtc" },
744 { .compatible = "allwinner,sun8i-r40-rtc" },
745 { .compatible = "allwinner,sun8i-v3-rtc" },
746 { .compatible = "allwinner,sun50i-h5-rtc" },
747 { .compatible = "allwinner,sun50i-h6-rtc" },
755 .name = "sun6i-rtc",