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