linux/drivers/rtc/rtc-goldfish.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* drivers/rtc/rtc-goldfish.c
   3 *
   4 * Copyright (C) 2007 Google, Inc.
   5 * Copyright (C) 2017 Imagination Technologies Ltd.
   6 */
   7
   8#include <linux/io.h>
   9#include <linux/module.h>
  10#include <linux/of.h>
  11#include <linux/platform_device.h>
  12#include <linux/rtc.h>
  13
  14#define TIMER_TIME_LOW          0x00    /* get low bits of current time  */
  15                                        /*   and update TIMER_TIME_HIGH  */
  16#define TIMER_TIME_HIGH 0x04    /* get high bits of time at last */
  17                                        /*   TIMER_TIME_LOW read         */
  18#define TIMER_ALARM_LOW 0x08    /* set low bits of alarm and     */
  19                                        /*   activate it                 */
  20#define TIMER_ALARM_HIGH        0x0c    /* set high bits of next alarm   */
  21#define TIMER_IRQ_ENABLED       0x10
  22#define TIMER_CLEAR_ALARM       0x14
  23#define TIMER_ALARM_STATUS      0x18
  24#define TIMER_CLEAR_INTERRUPT   0x1c
  25
  26struct goldfish_rtc {
  27        void __iomem *base;
  28        int irq;
  29        struct rtc_device *rtc;
  30};
  31
  32static int goldfish_rtc_read_alarm(struct device *dev,
  33                                   struct rtc_wkalrm *alrm)
  34{
  35        u64 rtc_alarm;
  36        u64 rtc_alarm_low;
  37        u64 rtc_alarm_high;
  38        void __iomem *base;
  39        struct goldfish_rtc *rtcdrv;
  40
  41        rtcdrv = dev_get_drvdata(dev);
  42        base = rtcdrv->base;
  43
  44        rtc_alarm_low = readl(base + TIMER_ALARM_LOW);
  45        rtc_alarm_high = readl(base + TIMER_ALARM_HIGH);
  46        rtc_alarm = (rtc_alarm_high << 32) | rtc_alarm_low;
  47
  48        do_div(rtc_alarm, NSEC_PER_SEC);
  49        memset(alrm, 0, sizeof(struct rtc_wkalrm));
  50
  51        rtc_time64_to_tm(rtc_alarm, &alrm->time);
  52
  53        if (readl(base + TIMER_ALARM_STATUS))
  54                alrm->enabled = 1;
  55        else
  56                alrm->enabled = 0;
  57
  58        return 0;
  59}
  60
  61static int goldfish_rtc_set_alarm(struct device *dev,
  62                                  struct rtc_wkalrm *alrm)
  63{
  64        struct goldfish_rtc *rtcdrv;
  65        u64 rtc_alarm64;
  66        u64 rtc_status_reg;
  67        void __iomem *base;
  68
  69        rtcdrv = dev_get_drvdata(dev);
  70        base = rtcdrv->base;
  71
  72        if (alrm->enabled) {
  73                rtc_alarm64 = rtc_tm_to_time64(&alrm->time) * NSEC_PER_SEC;
  74                writel((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH);
  75                writel(rtc_alarm64, base + TIMER_ALARM_LOW);
  76                writel(1, base + TIMER_IRQ_ENABLED);
  77        } else {
  78                /*
  79                 * if this function was called with enabled=0
  80                 * then it could mean that the application is
  81                 * trying to cancel an ongoing alarm
  82                 */
  83                rtc_status_reg = readl(base + TIMER_ALARM_STATUS);
  84                if (rtc_status_reg)
  85                        writel(1, base + TIMER_CLEAR_ALARM);
  86        }
  87
  88        return 0;
  89}
  90
  91static int goldfish_rtc_alarm_irq_enable(struct device *dev,
  92                                         unsigned int enabled)
  93{
  94        void __iomem *base;
  95        struct goldfish_rtc *rtcdrv;
  96
  97        rtcdrv = dev_get_drvdata(dev);
  98        base = rtcdrv->base;
  99
 100        if (enabled)
 101                writel(1, base + TIMER_IRQ_ENABLED);
 102        else
 103                writel(0, base + TIMER_IRQ_ENABLED);
 104
 105        return 0;
 106}
 107
 108static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id)
 109{
 110        struct goldfish_rtc *rtcdrv = dev_id;
 111        void __iomem *base = rtcdrv->base;
 112
 113        writel(1, base + TIMER_CLEAR_INTERRUPT);
 114
 115        rtc_update_irq(rtcdrv->rtc, 1, RTC_IRQF | RTC_AF);
 116
 117        return IRQ_HANDLED;
 118}
 119
 120static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm)
 121{
 122        struct goldfish_rtc *rtcdrv;
 123        void __iomem *base;
 124        u64 time_high;
 125        u64 time_low;
 126        u64 time;
 127
 128        rtcdrv = dev_get_drvdata(dev);
 129        base = rtcdrv->base;
 130
 131        time_low = readl(base + TIMER_TIME_LOW);
 132        time_high = readl(base + TIMER_TIME_HIGH);
 133        time = (time_high << 32) | time_low;
 134
 135        do_div(time, NSEC_PER_SEC);
 136
 137        rtc_time64_to_tm(time, tm);
 138
 139        return 0;
 140}
 141
 142static int goldfish_rtc_set_time(struct device *dev, struct rtc_time *tm)
 143{
 144        struct goldfish_rtc *rtcdrv;
 145        void __iomem *base;
 146        u64 now64;
 147
 148        rtcdrv = dev_get_drvdata(dev);
 149        base = rtcdrv->base;
 150
 151        now64 = rtc_tm_to_time64(tm) * NSEC_PER_SEC;
 152        writel((now64 >> 32), base + TIMER_TIME_HIGH);
 153        writel(now64, base + TIMER_TIME_LOW);
 154
 155        return 0;
 156}
 157
 158static const struct rtc_class_ops goldfish_rtc_ops = {
 159        .read_time      = goldfish_rtc_read_time,
 160        .set_time       = goldfish_rtc_set_time,
 161        .read_alarm     = goldfish_rtc_read_alarm,
 162        .set_alarm      = goldfish_rtc_set_alarm,
 163        .alarm_irq_enable = goldfish_rtc_alarm_irq_enable
 164};
 165
 166static int goldfish_rtc_probe(struct platform_device *pdev)
 167{
 168        struct goldfish_rtc *rtcdrv;
 169        int err;
 170
 171        rtcdrv = devm_kzalloc(&pdev->dev, sizeof(*rtcdrv), GFP_KERNEL);
 172        if (!rtcdrv)
 173                return -ENOMEM;
 174
 175        platform_set_drvdata(pdev, rtcdrv);
 176        rtcdrv->base = devm_platform_ioremap_resource(pdev, 0);
 177        if (IS_ERR(rtcdrv->base))
 178                return PTR_ERR(rtcdrv->base);
 179
 180        rtcdrv->irq = platform_get_irq(pdev, 0);
 181        if (rtcdrv->irq < 0)
 182                return -ENODEV;
 183
 184        rtcdrv->rtc = devm_rtc_allocate_device(&pdev->dev);
 185        if (IS_ERR(rtcdrv->rtc))
 186                return PTR_ERR(rtcdrv->rtc);
 187
 188        rtcdrv->rtc->ops = &goldfish_rtc_ops;
 189        rtcdrv->rtc->range_max = U64_MAX / NSEC_PER_SEC;
 190
 191        err = devm_request_irq(&pdev->dev, rtcdrv->irq,
 192                               goldfish_rtc_interrupt,
 193                               0, pdev->name, rtcdrv);
 194        if (err)
 195                return err;
 196
 197        return devm_rtc_register_device(rtcdrv->rtc);
 198}
 199
 200static const struct of_device_id goldfish_rtc_of_match[] = {
 201        { .compatible = "google,goldfish-rtc", },
 202        {},
 203};
 204MODULE_DEVICE_TABLE(of, goldfish_rtc_of_match);
 205
 206static struct platform_driver goldfish_rtc = {
 207        .probe = goldfish_rtc_probe,
 208        .driver = {
 209                .name = "goldfish_rtc",
 210                .of_match_table = goldfish_rtc_of_match,
 211        }
 212};
 213
 214module_platform_driver(goldfish_rtc);
 215
 216MODULE_LICENSE("GPL v2");
 217