Lines Matching +full:chip +full:- +full:relative

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 */
108 * The year parameter passed to the driver is usually an offset relative to
110 * relative to the minimum year allowed by the hardware.
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)
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()
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",
411 CLK_OF_DECLARE_DRIVER(sun8i_v3_rtc_clk, "allwinner,sun8i-v3-rtc",
416 struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id; in sun6i_rtc_alarmirq() local
420 spin_lock(&chip->lock); in sun6i_rtc_alarmirq()
421 val = readl(chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_alarmirq()
425 writel(val, chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_alarmirq()
427 rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); in sun6i_rtc_alarmirq()
431 spin_unlock(&chip->lock); in sun6i_rtc_alarmirq()
436 static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip) in sun6i_rtc_setaie() argument
449 chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_setaie()
452 spin_lock_irqsave(&chip->lock, flags); in sun6i_rtc_setaie()
453 writel(alrm_val, chip->base + SUN6I_ALRM_EN); in sun6i_rtc_setaie()
454 writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_setaie()
455 writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG); in sun6i_rtc_setaie()
456 spin_unlock_irqrestore(&chip->lock, flags); in sun6i_rtc_setaie()
461 struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); in sun6i_rtc_gettime() local
468 date = readl(chip->base + SUN6I_RTC_YMD); in sun6i_rtc_gettime()
469 time = readl(chip->base + SUN6I_RTC_HMS); in sun6i_rtc_gettime()
470 } while ((date != readl(chip->base + SUN6I_RTC_YMD)) || in sun6i_rtc_gettime()
471 (time != readl(chip->base + SUN6I_RTC_HMS))); in sun6i_rtc_gettime()
473 if (chip->flags & RTC_LINEAR_DAY) { in sun6i_rtc_gettime()
482 rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date); in sun6i_rtc_gettime()
483 rtc_tm->tm_mon = SUN6I_DATE_GET_MON_VALUE(date) - 1; in sun6i_rtc_gettime()
484 rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date); in sun6i_rtc_gettime()
487 * switch from (data_year->min)-relative offset to in sun6i_rtc_gettime()
488 * a (1900)-relative one in sun6i_rtc_gettime()
490 rtc_tm->tm_year += SUN6I_YEAR_OFF; in sun6i_rtc_gettime()
493 rtc_tm->tm_sec = SUN6I_TIME_GET_SEC_VALUE(time); in sun6i_rtc_gettime()
494 rtc_tm->tm_min = SUN6I_TIME_GET_MIN_VALUE(time); in sun6i_rtc_gettime()
495 rtc_tm->tm_hour = SUN6I_TIME_GET_HOUR_VALUE(time); in sun6i_rtc_gettime()
502 struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); in sun6i_rtc_getalarm() local
507 spin_lock_irqsave(&chip->lock, flags); in sun6i_rtc_getalarm()
508 alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_getalarm()
509 alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_getalarm()
510 spin_unlock_irqrestore(&chip->lock, flags); in sun6i_rtc_getalarm()
512 wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN); in sun6i_rtc_getalarm()
513 wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN); in sun6i_rtc_getalarm()
514 rtc_time64_to_tm(chip->alarm, &wkalrm->time); in sun6i_rtc_getalarm()
521 struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); in sun6i_rtc_setalarm() local
522 struct rtc_time *alrm_tm = &wkalrm->time; in sun6i_rtc_setalarm()
530 if (chip->flags & RTC_LINEAR_DAY) { in sun6i_rtc_setalarm()
535 counter_val_hms = SUN6I_TIME_SET_SEC_VALUE(alrm_tm->tm_sec) | in sun6i_rtc_setalarm()
536 SUN6I_TIME_SET_MIN_VALUE(alrm_tm->tm_min) | in sun6i_rtc_setalarm()
537 SUN6I_TIME_SET_HOUR_VALUE(alrm_tm->tm_hour); in sun6i_rtc_setalarm()
547 return -EINVAL; in sun6i_rtc_setalarm()
553 return -EINVAL; in sun6i_rtc_setalarm()
555 if ((time_set - time_now) > U32_MAX) { in sun6i_rtc_setalarm()
557 return -EINVAL; in sun6i_rtc_setalarm()
560 counter_val = time_set - time_now; in sun6i_rtc_setalarm()
563 sun6i_rtc_setaie(0, chip); in sun6i_rtc_setalarm()
564 writel(0, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_setalarm()
565 if (chip->flags & RTC_LINEAR_DAY) in sun6i_rtc_setalarm()
566 writel(0, chip->base + SUN6I_ALRM_COUNTER_HMS); in sun6i_rtc_setalarm()
569 writel(counter_val, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_setalarm()
570 if (chip->flags & RTC_LINEAR_DAY) in sun6i_rtc_setalarm()
571 writel(counter_val_hms, chip->base + SUN6I_ALRM_COUNTER_HMS); in sun6i_rtc_setalarm()
572 chip->alarm = time_set; in sun6i_rtc_setalarm()
574 sun6i_rtc_setaie(wkalrm->enabled, chip); in sun6i_rtc_setalarm()
579 static int sun6i_rtc_wait(struct sun6i_rtc_dev *chip, int offset, in sun6i_rtc_wait() argument
586 reg = readl(chip->base + offset); in sun6i_rtc_wait()
594 return -ETIMEDOUT; in sun6i_rtc_wait()
599 struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); in sun6i_rtc_settime() local
603 time = SUN6I_TIME_SET_SEC_VALUE(rtc_tm->tm_sec) | in sun6i_rtc_settime()
604 SUN6I_TIME_SET_MIN_VALUE(rtc_tm->tm_min) | in sun6i_rtc_settime()
605 SUN6I_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour); in sun6i_rtc_settime()
607 if (chip->flags & RTC_LINEAR_DAY) { in sun6i_rtc_settime()
611 rtc_tm->tm_year -= SUN6I_YEAR_OFF; in sun6i_rtc_settime()
612 rtc_tm->tm_mon += 1; in sun6i_rtc_settime()
614 date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | in sun6i_rtc_settime()
615 SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon) | in sun6i_rtc_settime()
616 SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year); in sun6i_rtc_settime()
618 if (is_leap_year(rtc_tm->tm_year + SUN6I_YEAR_MIN)) in sun6i_rtc_settime()
623 if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL, in sun6i_rtc_settime()
626 return -EBUSY; in sun6i_rtc_settime()
629 writel(time, chip->base + SUN6I_RTC_HMS); in sun6i_rtc_settime()
632 * After writing the RTC HH-MM-SS register, the in sun6i_rtc_settime()
637 if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL, in sun6i_rtc_settime()
640 return -ETIMEDOUT; in sun6i_rtc_settime()
643 writel(date, chip->base + SUN6I_RTC_YMD); in sun6i_rtc_settime()
646 * After writing the RTC YY-MM-DD register, the in sun6i_rtc_settime()
651 if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL, in sun6i_rtc_settime()
654 return -ETIMEDOUT; in sun6i_rtc_settime()
662 struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); in sun6i_rtc_alarm_irq_enable() local
665 sun6i_rtc_setaie(enabled, chip); in sun6i_rtc_alarm_irq_enable()
680 struct sun6i_rtc_dev *chip = priv; in sun6i_rtc_nvmem_read() local
685 val[i] = readl(chip->base + SUN6I_GP_DATA + offset + 4 * i); in sun6i_rtc_nvmem_read()
692 struct sun6i_rtc_dev *chip = priv; in sun6i_rtc_nvmem_write() local
697 writel(val[i], chip->base + SUN6I_GP_DATA + offset + 4 * i); in sun6i_rtc_nvmem_write()
715 struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); in sun6i_rtc_suspend() local
718 enable_irq_wake(chip->irq); in sun6i_rtc_suspend()
726 struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); in sun6i_rtc_resume() local
729 disable_irq_wake(chip->irq); in sun6i_rtc_resume()
747 struct sun6i_rtc_dev *chip = sun6i_rtc; in sun6i_rtc_probe() local
748 struct device *dev = &pdev->dev; in sun6i_rtc_probe()
767 if (!chip) { in sun6i_rtc_probe()
768 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); in sun6i_rtc_probe()
769 if (!chip) in sun6i_rtc_probe()
770 return -ENOMEM; in sun6i_rtc_probe()
772 spin_lock_init(&chip->lock); in sun6i_rtc_probe()
774 chip->base = devm_platform_ioremap_resource(pdev, 0); in sun6i_rtc_probe()
775 if (IS_ERR(chip->base)) in sun6i_rtc_probe()
776 return PTR_ERR(chip->base); in sun6i_rtc_probe()
779 ret = sun6i_rtc_ccu_probe(dev, chip->base); in sun6i_rtc_probe()
785 platform_set_drvdata(pdev, chip); in sun6i_rtc_probe()
787 chip->flags = (unsigned long)of_device_get_match_data(&pdev->dev); in sun6i_rtc_probe()
789 chip->irq = platform_get_irq(pdev, 0); in sun6i_rtc_probe()
790 if (chip->irq < 0) in sun6i_rtc_probe()
791 return chip->irq; in sun6i_rtc_probe()
793 ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq, in sun6i_rtc_probe()
794 0, dev_name(&pdev->dev), chip); in sun6i_rtc_probe()
796 dev_err(&pdev->dev, "Could not request IRQ\n"); in sun6i_rtc_probe()
801 writel(0, chip->base + SUN6I_ALRM_COUNTER); in sun6i_rtc_probe()
804 writel(0, chip->base + SUN6I_ALRM_EN); in sun6i_rtc_probe()
807 writel(0, chip->base + SUN6I_ALRM_IRQ_EN); in sun6i_rtc_probe()
810 writel(0, chip->base + SUN6I_ALRM1_EN); in sun6i_rtc_probe()
813 writel(0, chip->base + SUN6I_ALRM1_IRQ_EN); in sun6i_rtc_probe()
817 chip->base + SUN6I_ALRM_IRQ_STA); in sun6i_rtc_probe()
821 chip->base + SUN6I_ALRM1_IRQ_STA); in sun6i_rtc_probe()
824 writel(0, chip->base + SUN6I_ALARM_CONFIG); in sun6i_rtc_probe()
826 clk_prepare_enable(chip->losc); in sun6i_rtc_probe()
828 device_init_wakeup(&pdev->dev, 1); in sun6i_rtc_probe()
830 chip->rtc = devm_rtc_allocate_device(&pdev->dev); in sun6i_rtc_probe()
831 if (IS_ERR(chip->rtc)) in sun6i_rtc_probe()
832 return PTR_ERR(chip->rtc); in sun6i_rtc_probe()
834 chip->rtc->ops = &sun6i_rtc_ops; in sun6i_rtc_probe()
835 if (chip->flags & RTC_LINEAR_DAY) in sun6i_rtc_probe()
836 chip->rtc->range_max = (65536 * SECS_PER_DAY) - 1; in sun6i_rtc_probe()
838 chip->rtc->range_max = 2019686399LL; /* 2033-12-31 23:59:59 */ in sun6i_rtc_probe()
840 ret = devm_rtc_register_device(chip->rtc); in sun6i_rtc_probe()
844 sun6i_rtc_nvmem_cfg.priv = chip; in sun6i_rtc_probe()
845 ret = devm_rtc_nvmem_register(chip->rtc, &sun6i_rtc_nvmem_cfg); in sun6i_rtc_probe()
855 * registers available for non-volatile storage, but experiments show
859 { .compatible = "allwinner,sun6i-a31-rtc" },
860 { .compatible = "allwinner,sun8i-a23-rtc" },
861 { .compatible = "allwinner,sun8i-h3-rtc" },
862 { .compatible = "allwinner,sun8i-r40-rtc" },
863 { .compatible = "allwinner,sun8i-v3-rtc" },
864 { .compatible = "allwinner,sun50i-h5-rtc" },
865 { .compatible = "allwinner,sun50i-h6-rtc" },
866 { .compatible = "allwinner,sun50i-h616-rtc",
868 { .compatible = "allwinner,sun50i-r329-rtc",
877 .name = "sun6i-rtc",