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>
16 #include <linux/clk/sunxi-ng.h>
29 #include <linux/rtc.h>
46 /* RTC */
74 /* General-purpose data */
113 * The year range is 1970 - 2033. This range is selected to match Allwinner's
117 #define SUN6I_YEAR_OFF (SUN6I_YEAR_MIN - 1900)
124 * - number of GPIO pins that can be configured to hold a certain level
125 * - crypto-key related registers (H5, H6)
126 * - boot process related (super standby, secondary processor entry address)
128 * - SYS power domain controls (R40)
129 * - DCXO controls (H6)
130 * - RC oscillator calibration (H6)
147 struct rtc_device *rtc; member
167 struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw); in sun6i_rtc_osc_recalc_rate() local
170 val = readl(rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_osc_recalc_rate()
174 if (rtc->data->fixed_prescaler) in sun6i_rtc_osc_recalc_rate()
175 parent_rate /= rtc->data->fixed_prescaler; in sun6i_rtc_osc_recalc_rate()
177 if (rtc->data->has_prescaler) { in sun6i_rtc_osc_recalc_rate()
178 val = readl(rtc->base + SUN6I_LOSC_CLK_PRESCAL); in sun6i_rtc_osc_recalc_rate()
187 struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw); in sun6i_rtc_osc_get_parent() local
189 return readl(rtc->base + SUN6I_LOSC_CTRL) & SUN6I_LOSC_CTRL_EXT_OSC; in sun6i_rtc_osc_get_parent()
194 struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw); in sun6i_rtc_osc_set_parent() local
199 return -EINVAL; in sun6i_rtc_osc_set_parent()
201 spin_lock_irqsave(&rtc->lock, flags); in sun6i_rtc_osc_set_parent()
202 val = readl(rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_osc_set_parent()
206 if (rtc->data->has_losc_en) { in sun6i_rtc_osc_set_parent()
210 writel(val, rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_osc_set_parent()
211 spin_unlock_irqrestore(&rtc->lock, flags); in sun6i_rtc_osc_set_parent()
227 struct sun6i_rtc_dev *rtc; in sun6i_rtc_clk_init() local
232 const char *iosc_name = "rtc-int-osc"; in sun6i_rtc_clk_init()
233 const char *clkout_name = "osc32k-out"; in sun6i_rtc_clk_init()
237 rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); in sun6i_rtc_clk_init()
238 if (!rtc) in sun6i_rtc_clk_init()
241 rtc->data = data; in sun6i_rtc_clk_init()
244 kfree(rtc); in sun6i_rtc_clk_init()
248 spin_lock_init(&rtc->lock); in sun6i_rtc_clk_init()
250 rtc->base = of_io_request_and_map(node, 0, of_node_full_name(node)); in sun6i_rtc_clk_init()
251 if (IS_ERR(rtc->base)) { in sun6i_rtc_clk_init()
252 pr_crit("Can't map RTC registers"); in sun6i_rtc_clk_init()
257 if (rtc->data->has_auto_swt) { in sun6i_rtc_clk_init()
258 /* Bypass auto-switch to int osc, on ext losc failure */ in sun6i_rtc_clk_init()
260 writel(reg, rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_clk_init()
266 if (rtc->data->has_losc_en) in sun6i_rtc_clk_init()
269 writel(reg, rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_clk_init()
272 sun6i_rtc = rtc; in sun6i_rtc_clk_init()
275 if (rtc->data->export_iosc) in sun6i_rtc_clk_init()
276 of_property_read_string_index(node, "clock-output-names", 2, in sun6i_rtc_clk_init()
279 rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL, in sun6i_rtc_clk_init()
282 rtc->data->rc_osc_rate, in sun6i_rtc_clk_init()
284 if (IS_ERR(rtc->int_osc)) { in sun6i_rtc_clk_init()
289 parents[0] = clk_hw_get_name(rtc->int_osc); in sun6i_rtc_clk_init()
293 rtc->hw.init = &init; in sun6i_rtc_clk_init()
298 of_property_read_string_index(node, "clock-output-names", 0, in sun6i_rtc_clk_init()
301 rtc->losc = clk_register(NULL, &rtc->hw); in sun6i_rtc_clk_init()
302 if (IS_ERR(rtc->losc)) { in sun6i_rtc_clk_init()
307 of_property_read_string_index(node, "clock-output-names", 1, in sun6i_rtc_clk_init()
309 rtc->ext_losc = clk_register_gate(NULL, clkout_name, init.name, in sun6i_rtc_clk_init()
310 0, rtc->base + SUN6I_LOSC_OUT_GATING, in sun6i_rtc_clk_init()
312 &rtc->lock); in sun6i_rtc_clk_init()
313 if (IS_ERR(rtc->ext_losc)) { in sun6i_rtc_clk_init()
318 clk_data->num = 2; in sun6i_rtc_clk_init()
319 clk_data->hws[0] = &rtc->hw; in sun6i_rtc_clk_init()
320 clk_data->hws[1] = __clk_get_hw(rtc->ext_losc); in sun6i_rtc_clk_init()
321 if (rtc->data->export_iosc) { in sun6i_rtc_clk_init()
322 clk_data->hws[2] = rtc->int_osc; in sun6i_rtc_clk_init()
323 clk_data->num = 3; in sun6i_rtc_clk_init()
329 clk_hw_unregister_fixed_rate(rtc->int_osc); in sun6i_rtc_clk_init()
343 CLK_OF_DECLARE_DRIVER(sun6i_a31_rtc_clk, "allwinner,sun6i-a31-rtc",
356 CLK_OF_DECLARE_DRIVER(sun8i_a23_rtc_clk, "allwinner,sun8i-a23-rtc",
371 CLK_OF_DECLARE_DRIVER(sun8i_h3_rtc_clk, "allwinner,sun8i-h3-rtc",
374 CLK_OF_DECLARE_DRIVER(sun50i_h5_rtc_clk, "allwinner,sun50i-h5-rtc",
391 CLK_OF_DECLARE_DRIVER(sun50i_h6_rtc_clk, "allwinner,sun50i-h6-rtc",
395 * The R40 user manual is self-conflicting on whether the prescaler is
397 * is also a configurable divider in the RTC block.
407 CLK_OF_DECLARE_DRIVER(sun8i_r40_rtc_clk, "allwinner,sun8i-r40-rtc",
419 CLK_OF_DECLARE_DRIVER(sun8i_v3_rtc_clk, "allwinner,sun8i-v3-rtc",
428 spin_lock(&chip->lock); in sun6i_rtc_alarmirq()
429 val = readl(chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_alarmirq()
433 writel(val, chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_alarmirq()
435 rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); in sun6i_rtc_alarmirq()
439 spin_unlock(&chip->lock); in sun6i_rtc_alarmirq()
457 chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_setaie()
460 spin_lock_irqsave(&chip->lock, flags); in sun6i_rtc_setaie()
461 writel(alrm_val, chip->base + SUN6I_ALRM_EN); in sun6i_rtc_setaie()
462 writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_setaie()
463 writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG); in sun6i_rtc_setaie()
464 spin_unlock_irqrestore(&chip->lock, flags); in sun6i_rtc_setaie()
476 date = readl(chip->base + SUN6I_RTC_YMD); in sun6i_rtc_gettime()
477 time = readl(chip->base + SUN6I_RTC_HMS); in sun6i_rtc_gettime()
478 } while ((date != readl(chip->base + SUN6I_RTC_YMD)) || in sun6i_rtc_gettime()
479 (time != readl(chip->base + SUN6I_RTC_HMS))); in sun6i_rtc_gettime()
481 if (chip->flags & RTC_LINEAR_DAY) { in sun6i_rtc_gettime()
490 rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date); in sun6i_rtc_gettime()
491 rtc_tm->tm_mon = SUN6I_DATE_GET_MON_VALUE(date) - 1; in sun6i_rtc_gettime()
492 rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date); in sun6i_rtc_gettime()
495 * switch from (data_year->min)-relative offset to in sun6i_rtc_gettime()
496 * a (1900)-relative one in sun6i_rtc_gettime()
498 rtc_tm->tm_year += SUN6I_YEAR_OFF; in sun6i_rtc_gettime()
501 rtc_tm->tm_sec = SUN6I_TIME_GET_SEC_VALUE(time); in sun6i_rtc_gettime()
502 rtc_tm->tm_min = SUN6I_TIME_GET_MIN_VALUE(time); in sun6i_rtc_gettime()
503 rtc_tm->tm_hour = SUN6I_TIME_GET_HOUR_VALUE(time); in sun6i_rtc_gettime()
515 spin_lock_irqsave(&chip->lock, flags); in sun6i_rtc_getalarm()
516 alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_getalarm()
517 alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_getalarm()
518 spin_unlock_irqrestore(&chip->lock, flags); in sun6i_rtc_getalarm()
520 wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN); in sun6i_rtc_getalarm()
521 wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN); in sun6i_rtc_getalarm()
522 rtc_time64_to_tm(chip->alarm, &wkalrm->time); in sun6i_rtc_getalarm()
530 struct rtc_time *alrm_tm = &wkalrm->time; in sun6i_rtc_setalarm()
538 if (chip->flags & RTC_LINEAR_DAY) { in sun6i_rtc_setalarm()
543 counter_val_hms = SUN6I_TIME_SET_SEC_VALUE(alrm_tm->tm_sec) | in sun6i_rtc_setalarm()
544 SUN6I_TIME_SET_MIN_VALUE(alrm_tm->tm_min) | in sun6i_rtc_setalarm()
545 SUN6I_TIME_SET_HOUR_VALUE(alrm_tm->tm_hour); in sun6i_rtc_setalarm()
555 return -EINVAL; in sun6i_rtc_setalarm()
561 return -EINVAL; in sun6i_rtc_setalarm()
563 if ((time_set - time_now) > U32_MAX) { in sun6i_rtc_setalarm()
565 return -EINVAL; in sun6i_rtc_setalarm()
568 counter_val = time_set - time_now; in sun6i_rtc_setalarm()
572 writel(0, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_setalarm()
573 if (chip->flags & RTC_LINEAR_DAY) in sun6i_rtc_setalarm()
574 writel(0, chip->base + SUN6I_ALRM_COUNTER_HMS); in sun6i_rtc_setalarm()
577 writel(counter_val, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_setalarm()
578 if (chip->flags & RTC_LINEAR_DAY) in sun6i_rtc_setalarm()
579 writel(counter_val_hms, chip->base + SUN6I_ALRM_COUNTER_HMS); in sun6i_rtc_setalarm()
580 chip->alarm = time_set; in sun6i_rtc_setalarm()
582 sun6i_rtc_setaie(wkalrm->enabled, chip); in sun6i_rtc_setalarm()
594 reg = readl(chip->base + offset); in sun6i_rtc_wait()
602 return -ETIMEDOUT; in sun6i_rtc_wait()
611 time = SUN6I_TIME_SET_SEC_VALUE(rtc_tm->tm_sec) | in sun6i_rtc_settime()
612 SUN6I_TIME_SET_MIN_VALUE(rtc_tm->tm_min) | in sun6i_rtc_settime()
613 SUN6I_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour); in sun6i_rtc_settime()
615 if (chip->flags & RTC_LINEAR_DAY) { in sun6i_rtc_settime()
619 rtc_tm->tm_year -= SUN6I_YEAR_OFF; in sun6i_rtc_settime()
620 rtc_tm->tm_mon += 1; in sun6i_rtc_settime()
622 date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | in sun6i_rtc_settime()
623 SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon) | in sun6i_rtc_settime()
624 SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year); in sun6i_rtc_settime()
626 if (is_leap_year(rtc_tm->tm_year + SUN6I_YEAR_MIN)) in sun6i_rtc_settime()
633 dev_err(dev, "rtc is still busy.\n"); in sun6i_rtc_settime()
634 return -EBUSY; in sun6i_rtc_settime()
637 writel(time, chip->base + SUN6I_RTC_HMS); in sun6i_rtc_settime()
640 * After writing the RTC HH-MM-SS register, the in sun6i_rtc_settime()
647 dev_err(dev, "Failed to set rtc time.\n"); in sun6i_rtc_settime()
648 return -ETIMEDOUT; in sun6i_rtc_settime()
651 writel(date, chip->base + SUN6I_RTC_YMD); in sun6i_rtc_settime()
654 * After writing the RTC YY-MM-DD register, the in sun6i_rtc_settime()
661 dev_err(dev, "Failed to set rtc time.\n"); in sun6i_rtc_settime()
662 return -ETIMEDOUT; in sun6i_rtc_settime()
693 val[i] = readl(chip->base + SUN6I_GP_DATA + offset + 4 * i); in sun6i_rtc_nvmem_read()
705 writel(val[i], chip->base + SUN6I_GP_DATA + offset + 4 * i); in sun6i_rtc_nvmem_write()
720 /* Enable IRQ wake on suspend, to wake up from RTC. */
726 enable_irq_wake(chip->irq); in sun6i_rtc_suspend()
737 disable_irq_wake(chip->irq); in sun6i_rtc_resume()
756 struct device *dev = &pdev->dev; in sun6i_rtc_probe()
776 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); in sun6i_rtc_probe()
778 return -ENOMEM; in sun6i_rtc_probe()
780 spin_lock_init(&chip->lock); in sun6i_rtc_probe()
782 chip->base = devm_platform_ioremap_resource(pdev, 0); in sun6i_rtc_probe()
783 if (IS_ERR(chip->base)) in sun6i_rtc_probe()
784 return PTR_ERR(chip->base); in sun6i_rtc_probe()
787 ret = sun6i_rtc_ccu_probe(dev, chip->base); in sun6i_rtc_probe()
795 chip->flags = (unsigned long)of_device_get_match_data(&pdev->dev); in sun6i_rtc_probe()
797 chip->irq = platform_get_irq(pdev, 0); in sun6i_rtc_probe()
798 if (chip->irq < 0) in sun6i_rtc_probe()
799 return chip->irq; in sun6i_rtc_probe()
801 ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq, in sun6i_rtc_probe()
802 0, dev_name(&pdev->dev), chip); in sun6i_rtc_probe()
804 dev_err(&pdev->dev, "Could not request IRQ\n"); in sun6i_rtc_probe()
809 writel(0, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_probe()
812 writel(0, chip->base + SUN6I_ALRM_EN); in sun6i_rtc_probe()
815 writel(0, chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_probe()
818 writel(0, chip->base + SUN6I_ALRM1_EN); in sun6i_rtc_probe()
821 writel(0, chip->base + SUN6I_ALRM1_IRQ_EN); in sun6i_rtc_probe()
825 chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_probe()
829 chip->base + SUN6I_ALRM1_IRQ_STA); in sun6i_rtc_probe()
832 writel(0, chip->base + SUN6I_ALARM_CONFIG); in sun6i_rtc_probe()
834 clk_prepare_enable(chip->losc); in sun6i_rtc_probe()
836 device_init_wakeup(&pdev->dev, 1); in sun6i_rtc_probe()
838 chip->rtc = devm_rtc_allocate_device(&pdev->dev); in sun6i_rtc_probe()
839 if (IS_ERR(chip->rtc)) in sun6i_rtc_probe()
840 return PTR_ERR(chip->rtc); in sun6i_rtc_probe()
842 chip->rtc->ops = &sun6i_rtc_ops; in sun6i_rtc_probe()
843 if (chip->flags & RTC_LINEAR_DAY) in sun6i_rtc_probe()
844 chip->rtc->range_max = (65536 * SECS_PER_DAY) - 1; in sun6i_rtc_probe()
846 chip->rtc->range_max = 2019686399LL; /* 2033-12-31 23:59:59 */ in sun6i_rtc_probe()
848 ret = devm_rtc_register_device(chip->rtc); in sun6i_rtc_probe()
853 ret = devm_rtc_nvmem_register(chip->rtc, &sun6i_rtc_nvmem_cfg); in sun6i_rtc_probe()
857 dev_info(&pdev->dev, "RTC enabled\n"); in sun6i_rtc_probe()
863 * As far as RTC functionality goes, all models are the same. The
865 * registers available for non-volatile storage, but experiments show
869 { .compatible = "allwinner,sun6i-a31-rtc" },
870 { .compatible = "allwinner,sun8i-a23-rtc" },
871 { .compatible = "allwinner,sun8i-h3-rtc" },
872 { .compatible = "allwinner,sun8i-r40-rtc" },
873 { .compatible = "allwinner,sun8i-v3-rtc" },
874 { .compatible = "allwinner,sun50i-h5-rtc" },
875 { .compatible = "allwinner,sun50i-h6-rtc" },
876 { .compatible = "allwinner,sun50i-h616-rtc",
878 { .compatible = "allwinner,sun50i-r329-rtc",
887 .name = "sun6i-rtc",