Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* drivers/rtc/rtc-goldfish.c
0003  *
0004  * Copyright (C) 2007 Google, Inc.
0005  * Copyright (C) 2017 Imagination Technologies Ltd.
0006  */
0007 
0008 #include <linux/io.h>
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/rtc.h>
0013 #include <linux/goldfish.h>
0014 #include <clocksource/timer-goldfish.h>
0015 
0016 struct goldfish_rtc {
0017     void __iomem *base;
0018     int irq;
0019     struct rtc_device *rtc;
0020 };
0021 
0022 static int goldfish_rtc_read_alarm(struct device *dev,
0023                    struct rtc_wkalrm *alrm)
0024 {
0025     u64 rtc_alarm;
0026     u64 rtc_alarm_low;
0027     u64 rtc_alarm_high;
0028     void __iomem *base;
0029     struct goldfish_rtc *rtcdrv;
0030 
0031     rtcdrv = dev_get_drvdata(dev);
0032     base = rtcdrv->base;
0033 
0034     rtc_alarm_low = gf_ioread32(base + TIMER_ALARM_LOW);
0035     rtc_alarm_high = gf_ioread32(base + TIMER_ALARM_HIGH);
0036     rtc_alarm = (rtc_alarm_high << 32) | rtc_alarm_low;
0037 
0038     do_div(rtc_alarm, NSEC_PER_SEC);
0039     memset(alrm, 0, sizeof(struct rtc_wkalrm));
0040 
0041     rtc_time64_to_tm(rtc_alarm, &alrm->time);
0042 
0043     if (gf_ioread32(base + TIMER_ALARM_STATUS))
0044         alrm->enabled = 1;
0045     else
0046         alrm->enabled = 0;
0047 
0048     return 0;
0049 }
0050 
0051 static int goldfish_rtc_set_alarm(struct device *dev,
0052                   struct rtc_wkalrm *alrm)
0053 {
0054     struct goldfish_rtc *rtcdrv;
0055     u64 rtc_alarm64;
0056     u64 rtc_status_reg;
0057     void __iomem *base;
0058 
0059     rtcdrv = dev_get_drvdata(dev);
0060     base = rtcdrv->base;
0061 
0062     if (alrm->enabled) {
0063         rtc_alarm64 = rtc_tm_to_time64(&alrm->time) * NSEC_PER_SEC;
0064         gf_iowrite32((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH);
0065         gf_iowrite32(rtc_alarm64, base + TIMER_ALARM_LOW);
0066         gf_iowrite32(1, base + TIMER_IRQ_ENABLED);
0067     } else {
0068         /*
0069          * if this function was called with enabled=0
0070          * then it could mean that the application is
0071          * trying to cancel an ongoing alarm
0072          */
0073         rtc_status_reg = gf_ioread32(base + TIMER_ALARM_STATUS);
0074         if (rtc_status_reg)
0075             gf_iowrite32(1, base + TIMER_CLEAR_ALARM);
0076     }
0077 
0078     return 0;
0079 }
0080 
0081 static int goldfish_rtc_alarm_irq_enable(struct device *dev,
0082                      unsigned int enabled)
0083 {
0084     void __iomem *base;
0085     struct goldfish_rtc *rtcdrv;
0086 
0087     rtcdrv = dev_get_drvdata(dev);
0088     base = rtcdrv->base;
0089 
0090     if (enabled)
0091         gf_iowrite32(1, base + TIMER_IRQ_ENABLED);
0092     else
0093         gf_iowrite32(0, base + TIMER_IRQ_ENABLED);
0094 
0095     return 0;
0096 }
0097 
0098 static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id)
0099 {
0100     struct goldfish_rtc *rtcdrv = dev_id;
0101     void __iomem *base = rtcdrv->base;
0102 
0103     gf_iowrite32(1, base + TIMER_CLEAR_INTERRUPT);
0104 
0105     rtc_update_irq(rtcdrv->rtc, 1, RTC_IRQF | RTC_AF);
0106 
0107     return IRQ_HANDLED;
0108 }
0109 
0110 static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm)
0111 {
0112     struct goldfish_rtc *rtcdrv;
0113     void __iomem *base;
0114     u64 time_high;
0115     u64 time_low;
0116     u64 time;
0117 
0118     rtcdrv = dev_get_drvdata(dev);
0119     base = rtcdrv->base;
0120 
0121     time_low = gf_ioread32(base + TIMER_TIME_LOW);
0122     time_high = gf_ioread32(base + TIMER_TIME_HIGH);
0123     time = (time_high << 32) | time_low;
0124 
0125     do_div(time, NSEC_PER_SEC);
0126 
0127     rtc_time64_to_tm(time, tm);
0128 
0129     return 0;
0130 }
0131 
0132 static int goldfish_rtc_set_time(struct device *dev, struct rtc_time *tm)
0133 {
0134     struct goldfish_rtc *rtcdrv;
0135     void __iomem *base;
0136     u64 now64;
0137 
0138     rtcdrv = dev_get_drvdata(dev);
0139     base = rtcdrv->base;
0140 
0141     now64 = rtc_tm_to_time64(tm) * NSEC_PER_SEC;
0142     gf_iowrite32((now64 >> 32), base + TIMER_TIME_HIGH);
0143     gf_iowrite32(now64, base + TIMER_TIME_LOW);
0144 
0145     return 0;
0146 }
0147 
0148 static const struct rtc_class_ops goldfish_rtc_ops = {
0149     .read_time  = goldfish_rtc_read_time,
0150     .set_time   = goldfish_rtc_set_time,
0151     .read_alarm = goldfish_rtc_read_alarm,
0152     .set_alarm  = goldfish_rtc_set_alarm,
0153     .alarm_irq_enable = goldfish_rtc_alarm_irq_enable
0154 };
0155 
0156 static int goldfish_rtc_probe(struct platform_device *pdev)
0157 {
0158     struct goldfish_rtc *rtcdrv;
0159     int err;
0160 
0161     rtcdrv = devm_kzalloc(&pdev->dev, sizeof(*rtcdrv), GFP_KERNEL);
0162     if (!rtcdrv)
0163         return -ENOMEM;
0164 
0165     platform_set_drvdata(pdev, rtcdrv);
0166     rtcdrv->base = devm_platform_ioremap_resource(pdev, 0);
0167     if (IS_ERR(rtcdrv->base))
0168         return PTR_ERR(rtcdrv->base);
0169 
0170     rtcdrv->irq = platform_get_irq(pdev, 0);
0171     if (rtcdrv->irq < 0)
0172         return -ENODEV;
0173 
0174     rtcdrv->rtc = devm_rtc_allocate_device(&pdev->dev);
0175     if (IS_ERR(rtcdrv->rtc))
0176         return PTR_ERR(rtcdrv->rtc);
0177 
0178     rtcdrv->rtc->ops = &goldfish_rtc_ops;
0179     rtcdrv->rtc->range_max = U64_MAX / NSEC_PER_SEC;
0180 
0181     err = devm_request_irq(&pdev->dev, rtcdrv->irq,
0182                    goldfish_rtc_interrupt,
0183                    0, pdev->name, rtcdrv);
0184     if (err)
0185         return err;
0186 
0187     return devm_rtc_register_device(rtcdrv->rtc);
0188 }
0189 
0190 static const struct of_device_id goldfish_rtc_of_match[] = {
0191     { .compatible = "google,goldfish-rtc", },
0192     {},
0193 };
0194 MODULE_DEVICE_TABLE(of, goldfish_rtc_of_match);
0195 
0196 static struct platform_driver goldfish_rtc = {
0197     .probe = goldfish_rtc_probe,
0198     .driver = {
0199         .name = "goldfish_rtc",
0200         .of_match_table = goldfish_rtc_of_match,
0201     }
0202 };
0203 
0204 module_platform_driver(goldfish_rtc);
0205 
0206 MODULE_LICENSE("GPL v2");