linux/drivers/rtc/rtc-au1xxx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Au1xxx counter0 (aka Time-Of-Year counter) RTC interface driver.
   4 *
   5 * Copyright (C) 2008 Manuel Lauss <mano@roarinelk.homelinux.net>
   6 */
   7
   8/* All current Au1xxx SoCs have 2 counters fed by an external 32.768 kHz
   9 * crystal. Counter 0, which keeps counting during sleep/powerdown, is
  10 * used to count seconds since the beginning of the unix epoch.
  11 *
  12 * The counters must be configured and enabled by bootloader/board code;
  13 * no checks as to whether they really get a proper 32.768kHz clock are
  14 * made as this would take far too long.
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/kernel.h>
  19#include <linux/rtc.h>
  20#include <linux/init.h>
  21#include <linux/platform_device.h>
  22#include <linux/io.h>
  23#include <asm/mach-au1x00/au1000.h>
  24
  25/* 32kHz clock enabled and detected */
  26#define CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S)
  27
  28static int au1xtoy_rtc_read_time(struct device *dev, struct rtc_time *tm)
  29{
  30        unsigned long t;
  31
  32        t = alchemy_rdsys(AU1000_SYS_TOYREAD);
  33
  34        rtc_time64_to_tm(t, tm);
  35
  36        return 0;
  37}
  38
  39static int au1xtoy_rtc_set_time(struct device *dev, struct rtc_time *tm)
  40{
  41        unsigned long t;
  42
  43        t = rtc_tm_to_time64(tm);
  44
  45        alchemy_wrsys(t, AU1000_SYS_TOYWRITE);
  46
  47        /* wait for the pending register write to succeed.  This can
  48         * take up to 6 seconds...
  49         */
  50        while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_C0S)
  51                msleep(1);
  52
  53        return 0;
  54}
  55
  56static const struct rtc_class_ops au1xtoy_rtc_ops = {
  57        .read_time      = au1xtoy_rtc_read_time,
  58        .set_time       = au1xtoy_rtc_set_time,
  59};
  60
  61static int au1xtoy_rtc_probe(struct platform_device *pdev)
  62{
  63        struct rtc_device *rtcdev;
  64        unsigned long t;
  65
  66        t = alchemy_rdsys(AU1000_SYS_CNTRCTRL);
  67        if (!(t & CNTR_OK)) {
  68                dev_err(&pdev->dev, "counters not working; aborting.\n");
  69                return -ENODEV;
  70        }
  71
  72        /* set counter0 tickrate to 1Hz if necessary */
  73        if (alchemy_rdsys(AU1000_SYS_TOYTRIM) != 32767) {
  74                /* wait until hardware gives access to TRIM register */
  75                t = 0x00100000;
  76                while ((alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_T0S) && --t)
  77                        msleep(1);
  78
  79                if (!t) {
  80                        /* timed out waiting for register access; assume
  81                         * counters are unusable.
  82                         */
  83                        dev_err(&pdev->dev, "timeout waiting for access\n");
  84                        return -ETIMEDOUT;
  85                }
  86
  87                /* set 1Hz TOY tick rate */
  88                alchemy_wrsys(32767, AU1000_SYS_TOYTRIM);
  89        }
  90
  91        /* wait until the hardware allows writes to the counter reg */
  92        while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_C0S)
  93                msleep(1);
  94
  95        rtcdev = devm_rtc_allocate_device(&pdev->dev);
  96        if (IS_ERR(rtcdev))
  97                return PTR_ERR(rtcdev);
  98
  99        rtcdev->ops = &au1xtoy_rtc_ops;
 100        rtcdev->range_max = U32_MAX;
 101
 102        platform_set_drvdata(pdev, rtcdev);
 103
 104        return devm_rtc_register_device(rtcdev);
 105}
 106
 107static struct platform_driver au1xrtc_driver = {
 108        .driver         = {
 109                .name   = "rtc-au1xxx",
 110        },
 111};
 112
 113module_platform_driver_probe(au1xrtc_driver, au1xtoy_rtc_probe);
 114
 115MODULE_DESCRIPTION("Au1xxx TOY-counter-based RTC driver");
 116MODULE_AUTHOR("Manuel Lauss <manuel.lauss@gmail.com>");
 117MODULE_LICENSE("GPL");
 118MODULE_ALIAS("platform:rtc-au1xxx");
 119