root/drivers/rtc/rtc-pl030.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pl030_interrupt
  2. pl030_read_alarm
  3. pl030_set_alarm
  4. pl030_read_time
  5. pl030_set_time
  6. pl030_probe
  7. pl030_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  linux/drivers/rtc/rtc-pl030.c
   4  *
   5  *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
   6  */
   7 #include <linux/module.h>
   8 #include <linux/rtc.h>
   9 #include <linux/init.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/amba/bus.h>
  12 #include <linux/io.h>
  13 #include <linux/slab.h>
  14 
  15 #define RTC_DR          (0)
  16 #define RTC_MR          (4)
  17 #define RTC_STAT        (8)
  18 #define RTC_EOI         (8)
  19 #define RTC_LR          (12)
  20 #define RTC_CR          (16)
  21 #define RTC_CR_MIE      (1 << 0)
  22 
  23 struct pl030_rtc {
  24         struct rtc_device       *rtc;
  25         void __iomem            *base;
  26 };
  27 
  28 static irqreturn_t pl030_interrupt(int irq, void *dev_id)
  29 {
  30         struct pl030_rtc *rtc = dev_id;
  31         writel(0, rtc->base + RTC_EOI);
  32         return IRQ_HANDLED;
  33 }
  34 
  35 static int pl030_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  36 {
  37         struct pl030_rtc *rtc = dev_get_drvdata(dev);
  38 
  39         rtc_time_to_tm(readl(rtc->base + RTC_MR), &alrm->time);
  40         return 0;
  41 }
  42 
  43 static int pl030_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  44 {
  45         struct pl030_rtc *rtc = dev_get_drvdata(dev);
  46         unsigned long time;
  47         int ret;
  48 
  49         /*
  50          * At the moment, we can only deal with non-wildcarded alarm times.
  51          */
  52         ret = rtc_valid_tm(&alrm->time);
  53         if (ret == 0)
  54                 ret = rtc_tm_to_time(&alrm->time, &time);
  55         if (ret == 0)
  56                 writel(time, rtc->base + RTC_MR);
  57         return ret;
  58 }
  59 
  60 static int pl030_read_time(struct device *dev, struct rtc_time *tm)
  61 {
  62         struct pl030_rtc *rtc = dev_get_drvdata(dev);
  63 
  64         rtc_time_to_tm(readl(rtc->base + RTC_DR), tm);
  65 
  66         return 0;
  67 }
  68 
  69 /*
  70  * Set the RTC time.  Unfortunately, we can't accurately set
  71  * the point at which the counter updates.
  72  *
  73  * Also, since RTC_LR is transferred to RTC_CR on next rising
  74  * edge of the 1Hz clock, we must write the time one second
  75  * in advance.
  76  */
  77 static int pl030_set_time(struct device *dev, struct rtc_time *tm)
  78 {
  79         struct pl030_rtc *rtc = dev_get_drvdata(dev);
  80         unsigned long time;
  81         int ret;
  82 
  83         ret = rtc_tm_to_time(tm, &time);
  84         if (ret == 0)
  85                 writel(time + 1, rtc->base + RTC_LR);
  86 
  87         return ret;
  88 }
  89 
  90 static const struct rtc_class_ops pl030_ops = {
  91         .read_time      = pl030_read_time,
  92         .set_time       = pl030_set_time,
  93         .read_alarm     = pl030_read_alarm,
  94         .set_alarm      = pl030_set_alarm,
  95 };
  96 
  97 static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
  98 {
  99         struct pl030_rtc *rtc;
 100         int ret;
 101 
 102         ret = amba_request_regions(dev, NULL);
 103         if (ret)
 104                 goto err_req;
 105 
 106         rtc = devm_kzalloc(&dev->dev, sizeof(*rtc), GFP_KERNEL);
 107         if (!rtc) {
 108                 ret = -ENOMEM;
 109                 goto err_rtc;
 110         }
 111 
 112         rtc->rtc = devm_rtc_allocate_device(&dev->dev);
 113         if (IS_ERR(rtc->rtc)) {
 114                 ret = PTR_ERR(rtc->rtc);
 115                 goto err_rtc;
 116         }
 117 
 118         rtc->rtc->ops = &pl030_ops;
 119         rtc->base = ioremap(dev->res.start, resource_size(&dev->res));
 120         if (!rtc->base) {
 121                 ret = -ENOMEM;
 122                 goto err_rtc;
 123         }
 124 
 125         __raw_writel(0, rtc->base + RTC_CR);
 126         __raw_writel(0, rtc->base + RTC_EOI);
 127 
 128         amba_set_drvdata(dev, rtc);
 129 
 130         ret = request_irq(dev->irq[0], pl030_interrupt, 0,
 131                           "rtc-pl030", rtc);
 132         if (ret)
 133                 goto err_irq;
 134 
 135         ret = rtc_register_device(rtc->rtc);
 136         if (ret)
 137                 goto err_reg;
 138 
 139         return 0;
 140 
 141  err_reg:
 142         free_irq(dev->irq[0], rtc);
 143  err_irq:
 144         iounmap(rtc->base);
 145  err_rtc:
 146         amba_release_regions(dev);
 147  err_req:
 148         return ret;
 149 }
 150 
 151 static int pl030_remove(struct amba_device *dev)
 152 {
 153         struct pl030_rtc *rtc = amba_get_drvdata(dev);
 154 
 155         writel(0, rtc->base + RTC_CR);
 156 
 157         free_irq(dev->irq[0], rtc);
 158         iounmap(rtc->base);
 159         amba_release_regions(dev);
 160 
 161         return 0;
 162 }
 163 
 164 static struct amba_id pl030_ids[] = {
 165         {
 166                 .id     = 0x00041030,
 167                 .mask   = 0x000fffff,
 168         },
 169         { 0, 0 },
 170 };
 171 
 172 MODULE_DEVICE_TABLE(amba, pl030_ids);
 173 
 174 static struct amba_driver pl030_driver = {
 175         .drv            = {
 176                 .name   = "rtc-pl030",
 177         },
 178         .probe          = pl030_probe,
 179         .remove         = pl030_remove,
 180         .id_table       = pl030_ids,
 181 };
 182 
 183 module_amba_driver(pl030_driver);
 184 
 185 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 186 MODULE_DESCRIPTION("ARM AMBA PL030 RTC Driver");
 187 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */