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