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