Lines Matching +full:sun8i +full:- +full:r40 +full:- +full:can
1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (c) 2014, Chen-Yu Tsai <wens@csie.org>
7 * based on rtc-sunxi.c
15 #include <linux/clk-provider.h>
16 #include <linux/clk/sunxi-ng.h>
73 /* General-purpose data */
112 * The year range is 1970 - 2033. This range is selected to match Allwinner's
116 #define SUN6I_YEAR_OFF (SUN6I_YEAR_MIN - 1900)
123 * - number of GPIO pins that can be configured to hold a certain level
124 * - crypto-key related registers (H5, H6)
125 * - boot process related (super standby, secondary processor entry address)
126 * registers (R40, H6)
127 * - SYS power domain controls (R40)
128 * - DCXO controls (H6)
129 * - RC oscillator calibration (H6)
168 val = readl(rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_osc_recalc_rate()
172 if (rtc->data->fixed_prescaler) in sun6i_rtc_osc_recalc_rate()
173 parent_rate /= rtc->data->fixed_prescaler; in sun6i_rtc_osc_recalc_rate()
175 if (rtc->data->has_prescaler) { in sun6i_rtc_osc_recalc_rate()
176 val = readl(rtc->base + SUN6I_LOSC_CLK_PRESCAL); in sun6i_rtc_osc_recalc_rate()
187 return readl(rtc->base + SUN6I_LOSC_CTRL) & SUN6I_LOSC_CTRL_EXT_OSC; in sun6i_rtc_osc_get_parent()
197 return -EINVAL; in sun6i_rtc_osc_set_parent()
199 spin_lock_irqsave(&rtc->lock, flags); in sun6i_rtc_osc_set_parent()
200 val = readl(rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_osc_set_parent()
204 if (rtc->data->has_losc_en) { in sun6i_rtc_osc_set_parent()
208 writel(val, rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_osc_set_parent()
209 spin_unlock_irqrestore(&rtc->lock, flags); in sun6i_rtc_osc_set_parent()
231 const char *iosc_name = "rtc-int-osc"; in sun6i_rtc_clk_init()
232 const char *clkout_name = "osc32k-out"; in sun6i_rtc_clk_init()
240 rtc->data = data; in sun6i_rtc_clk_init()
247 spin_lock_init(&rtc->lock); in sun6i_rtc_clk_init()
249 rtc->base = of_io_request_and_map(node, 0, of_node_full_name(node)); in sun6i_rtc_clk_init()
250 if (IS_ERR(rtc->base)) { in sun6i_rtc_clk_init()
251 pr_crit("Can't map RTC registers"); in sun6i_rtc_clk_init()
256 if (rtc->data->has_auto_swt) { in sun6i_rtc_clk_init()
257 /* Bypass auto-switch to int osc, on ext losc failure */ in sun6i_rtc_clk_init()
259 writel(reg, rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_clk_init()
265 if (rtc->data->has_losc_en) in sun6i_rtc_clk_init()
268 writel(reg, rtc->base + SUN6I_LOSC_CTRL); in sun6i_rtc_clk_init()
273 of_property_read_string_index(node, "clock-output-names", 2, in sun6i_rtc_clk_init()
276 rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL, in sun6i_rtc_clk_init()
279 rtc->data->rc_osc_rate, in sun6i_rtc_clk_init()
281 if (IS_ERR(rtc->int_osc)) { in sun6i_rtc_clk_init()
286 parents[0] = clk_hw_get_name(rtc->int_osc); in sun6i_rtc_clk_init()
290 rtc->hw.init = &init; in sun6i_rtc_clk_init()
295 of_property_read_string_index(node, "clock-output-names", 0, in sun6i_rtc_clk_init()
298 rtc->losc = clk_register(NULL, &rtc->hw); in sun6i_rtc_clk_init()
299 if (IS_ERR(rtc->losc)) { in sun6i_rtc_clk_init()
304 of_property_read_string_index(node, "clock-output-names", 1, in sun6i_rtc_clk_init()
306 rtc->ext_losc = clk_register_gate(NULL, clkout_name, init.name, in sun6i_rtc_clk_init()
307 0, rtc->base + SUN6I_LOSC_OUT_GATING, in sun6i_rtc_clk_init()
309 &rtc->lock); in sun6i_rtc_clk_init()
310 if (IS_ERR(rtc->ext_losc)) { in sun6i_rtc_clk_init()
315 clk_data->num = 3; in sun6i_rtc_clk_init()
316 clk_data->hws[0] = &rtc->hw; in sun6i_rtc_clk_init()
317 clk_data->hws[1] = __clk_get_hw(rtc->ext_losc); in sun6i_rtc_clk_init()
318 clk_data->hws[2] = rtc->int_osc; in sun6i_rtc_clk_init()
323 clk_hw_unregister_fixed_rate(rtc->int_osc); in sun6i_rtc_clk_init()
337 CLK_OF_DECLARE_DRIVER(sun6i_a31_rtc_clk, "allwinner,sun6i-a31-rtc",
350 CLK_OF_DECLARE_DRIVER(sun8i_a23_rtc_clk, "allwinner,sun8i-a23-rtc",
364 CLK_OF_DECLARE_DRIVER(sun8i_h3_rtc_clk, "allwinner,sun8i-h3-rtc",
367 CLK_OF_DECLARE_DRIVER(sun50i_h5_rtc_clk, "allwinner,sun50i-h5-rtc",
383 CLK_OF_DECLARE_DRIVER(sun50i_h6_rtc_clk, "allwinner,sun50i-h6-rtc",
387 * The R40 user manual is self-conflicting on whether the prescaler is
399 CLK_OF_DECLARE_DRIVER(sun8i_r40_rtc_clk, "allwinner,sun8i-r40-rtc",
412 CLK_OF_DECLARE_DRIVER(sun8i_v3_rtc_clk, "allwinner,sun8i-v3-rtc",
421 spin_lock(&chip->lock); in sun6i_rtc_alarmirq()
422 val = readl(chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_alarmirq()
426 writel(val, chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_alarmirq()
428 rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); in sun6i_rtc_alarmirq()
432 spin_unlock(&chip->lock); in sun6i_rtc_alarmirq()
450 chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_setaie()
453 spin_lock_irqsave(&chip->lock, flags); in sun6i_rtc_setaie()
454 writel(alrm_val, chip->base + SUN6I_ALRM_EN); in sun6i_rtc_setaie()
455 writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_setaie()
456 writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG); in sun6i_rtc_setaie()
457 spin_unlock_irqrestore(&chip->lock, flags); in sun6i_rtc_setaie()
469 date = readl(chip->base + SUN6I_RTC_YMD); in sun6i_rtc_gettime()
470 time = readl(chip->base + SUN6I_RTC_HMS); in sun6i_rtc_gettime()
471 } while ((date != readl(chip->base + SUN6I_RTC_YMD)) || in sun6i_rtc_gettime()
472 (time != readl(chip->base + SUN6I_RTC_HMS))); in sun6i_rtc_gettime()
474 if (chip->flags & RTC_LINEAR_DAY) { in sun6i_rtc_gettime()
483 rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date); in sun6i_rtc_gettime()
484 rtc_tm->tm_mon = SUN6I_DATE_GET_MON_VALUE(date) - 1; in sun6i_rtc_gettime()
485 rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date); in sun6i_rtc_gettime()
488 * switch from (data_year->min)-relative offset to in sun6i_rtc_gettime()
489 * a (1900)-relative one in sun6i_rtc_gettime()
491 rtc_tm->tm_year += SUN6I_YEAR_OFF; in sun6i_rtc_gettime()
494 rtc_tm->tm_sec = SUN6I_TIME_GET_SEC_VALUE(time); in sun6i_rtc_gettime()
495 rtc_tm->tm_min = SUN6I_TIME_GET_MIN_VALUE(time); in sun6i_rtc_gettime()
496 rtc_tm->tm_hour = SUN6I_TIME_GET_HOUR_VALUE(time); in sun6i_rtc_gettime()
508 spin_lock_irqsave(&chip->lock, flags); in sun6i_rtc_getalarm()
509 alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_getalarm()
510 alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_getalarm()
511 spin_unlock_irqrestore(&chip->lock, flags); in sun6i_rtc_getalarm()
513 wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN); in sun6i_rtc_getalarm()
514 wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN); in sun6i_rtc_getalarm()
515 rtc_time64_to_tm(chip->alarm, &wkalrm->time); in sun6i_rtc_getalarm()
523 struct rtc_time *alrm_tm = &wkalrm->time; in sun6i_rtc_setalarm()
531 if (chip->flags & RTC_LINEAR_DAY) { in sun6i_rtc_setalarm()
536 counter_val_hms = SUN6I_TIME_SET_SEC_VALUE(alrm_tm->tm_sec) | in sun6i_rtc_setalarm()
537 SUN6I_TIME_SET_MIN_VALUE(alrm_tm->tm_min) | in sun6i_rtc_setalarm()
538 SUN6I_TIME_SET_HOUR_VALUE(alrm_tm->tm_hour); in sun6i_rtc_setalarm()
548 return -EINVAL; in sun6i_rtc_setalarm()
554 return -EINVAL; in sun6i_rtc_setalarm()
556 if ((time_set - time_now) > U32_MAX) { in sun6i_rtc_setalarm()
558 return -EINVAL; in sun6i_rtc_setalarm()
561 counter_val = time_set - time_now; in sun6i_rtc_setalarm()
565 writel(0, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_setalarm()
566 if (chip->flags & RTC_LINEAR_DAY) in sun6i_rtc_setalarm()
567 writel(0, chip->base + SUN6I_ALRM_COUNTER_HMS); in sun6i_rtc_setalarm()
570 writel(counter_val, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_setalarm()
571 if (chip->flags & RTC_LINEAR_DAY) in sun6i_rtc_setalarm()
572 writel(counter_val_hms, chip->base + SUN6I_ALRM_COUNTER_HMS); in sun6i_rtc_setalarm()
573 chip->alarm = time_set; in sun6i_rtc_setalarm()
575 sun6i_rtc_setaie(wkalrm->enabled, chip); in sun6i_rtc_setalarm()
587 reg = readl(chip->base + offset); in sun6i_rtc_wait()
595 return -ETIMEDOUT; in sun6i_rtc_wait()
604 time = SUN6I_TIME_SET_SEC_VALUE(rtc_tm->tm_sec) | in sun6i_rtc_settime()
605 SUN6I_TIME_SET_MIN_VALUE(rtc_tm->tm_min) | in sun6i_rtc_settime()
606 SUN6I_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour); in sun6i_rtc_settime()
608 if (chip->flags & RTC_LINEAR_DAY) { in sun6i_rtc_settime()
612 rtc_tm->tm_year -= SUN6I_YEAR_OFF; in sun6i_rtc_settime()
613 rtc_tm->tm_mon += 1; in sun6i_rtc_settime()
615 date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | in sun6i_rtc_settime()
616 SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon) | in sun6i_rtc_settime()
617 SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year); in sun6i_rtc_settime()
619 if (is_leap_year(rtc_tm->tm_year + SUN6I_YEAR_MIN)) in sun6i_rtc_settime()
627 return -EBUSY; in sun6i_rtc_settime()
630 writel(time, chip->base + SUN6I_RTC_HMS); in sun6i_rtc_settime()
633 * After writing the RTC HH-MM-SS register, the in sun6i_rtc_settime()
641 return -ETIMEDOUT; in sun6i_rtc_settime()
644 writel(date, chip->base + SUN6I_RTC_YMD); in sun6i_rtc_settime()
647 * After writing the RTC YY-MM-DD register, the in sun6i_rtc_settime()
655 return -ETIMEDOUT; in sun6i_rtc_settime()
686 val[i] = readl(chip->base + SUN6I_GP_DATA + offset + 4 * i); in sun6i_rtc_nvmem_read()
698 writel(val[i], chip->base + SUN6I_GP_DATA + offset + 4 * i); in sun6i_rtc_nvmem_write()
719 enable_irq_wake(chip->irq); in sun6i_rtc_suspend()
730 disable_irq_wake(chip->irq); in sun6i_rtc_resume()
749 struct device *dev = &pdev->dev; in sun6i_rtc_probe()
769 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); in sun6i_rtc_probe()
771 return -ENOMEM; in sun6i_rtc_probe()
773 spin_lock_init(&chip->lock); in sun6i_rtc_probe()
775 chip->base = devm_platform_ioremap_resource(pdev, 0); in sun6i_rtc_probe()
776 if (IS_ERR(chip->base)) in sun6i_rtc_probe()
777 return PTR_ERR(chip->base); in sun6i_rtc_probe()
780 ret = sun6i_rtc_ccu_probe(dev, chip->base); in sun6i_rtc_probe()
788 chip->flags = (unsigned long)of_device_get_match_data(&pdev->dev); in sun6i_rtc_probe()
790 chip->irq = platform_get_irq(pdev, 0); in sun6i_rtc_probe()
791 if (chip->irq < 0) in sun6i_rtc_probe()
792 return chip->irq; in sun6i_rtc_probe()
794 ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq, in sun6i_rtc_probe()
795 0, dev_name(&pdev->dev), chip); in sun6i_rtc_probe()
797 dev_err(&pdev->dev, "Could not request IRQ\n"); in sun6i_rtc_probe()
802 writel(0, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_probe()
805 writel(0, chip->base + SUN6I_ALRM_EN); in sun6i_rtc_probe()
808 writel(0, chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_probe()
811 writel(0, chip->base + SUN6I_ALRM1_EN); in sun6i_rtc_probe()
814 writel(0, chip->base + SUN6I_ALRM1_IRQ_EN); in sun6i_rtc_probe()
818 chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_probe()
822 chip->base + SUN6I_ALRM1_IRQ_STA); in sun6i_rtc_probe()
825 writel(0, chip->base + SUN6I_ALARM_CONFIG); in sun6i_rtc_probe()
827 clk_prepare_enable(chip->losc); in sun6i_rtc_probe()
829 device_init_wakeup(&pdev->dev, 1); in sun6i_rtc_probe()
831 chip->rtc = devm_rtc_allocate_device(&pdev->dev); in sun6i_rtc_probe()
832 if (IS_ERR(chip->rtc)) in sun6i_rtc_probe()
833 return PTR_ERR(chip->rtc); in sun6i_rtc_probe()
835 chip->rtc->ops = &sun6i_rtc_ops; in sun6i_rtc_probe()
836 if (chip->flags & RTC_LINEAR_DAY) in sun6i_rtc_probe()
837 chip->rtc->range_max = (65536 * SECS_PER_DAY) - 1; in sun6i_rtc_probe()
839 chip->rtc->range_max = 2019686399LL; /* 2033-12-31 23:59:59 */ in sun6i_rtc_probe()
841 ret = devm_rtc_register_device(chip->rtc); in sun6i_rtc_probe()
846 ret = devm_rtc_nvmem_register(chip->rtc, &sun6i_rtc_nvmem_cfg); in sun6i_rtc_probe()
856 * registers available for non-volatile storage, but experiments show
860 { .compatible = "allwinner,sun6i-a31-rtc" },
861 { .compatible = "allwinner,sun8i-a23-rtc" },
862 { .compatible = "allwinner,sun8i-h3-rtc" },
863 { .compatible = "allwinner,sun8i-r40-rtc" },
864 { .compatible = "allwinner,sun8i-v3-rtc" },
865 { .compatible = "allwinner,sun50i-h5-rtc" },
866 { .compatible = "allwinner,sun50i-h6-rtc" },
867 { .compatible = "allwinner,sun50i-h616-rtc",
869 { .compatible = "allwinner,sun50i-r329-rtc",
878 .name = "sun6i-rtc",