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