1/* 2 * An RTC driver for the AVR32 AT32AP700x processor series. 3 * 4 * Copyright (C) 2007 Atmel Corporation 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 as published 8 * by the Free Software Foundation. 9 */ 10 11#include <linux/module.h> 12#include <linux/kernel.h> 13#include <linux/platform_device.h> 14#include <linux/slab.h> 15#include <linux/rtc.h> 16#include <linux/io.h> 17 18/* 19 * This is a bare-bones RTC. It runs during most system sleep states, but has 20 * no battery backup and gets reset during system restart. It must be 21 * initialized from an external clock (network, I2C, etc) before it can be of 22 * much use. 23 * 24 * The alarm functionality is limited by the hardware, not supporting 25 * periodic interrupts. 26 */ 27 28#define RTC_CTRL 0x00 29#define RTC_CTRL_EN 0 30#define RTC_CTRL_PCLR 1 31#define RTC_CTRL_TOPEN 2 32#define RTC_CTRL_PSEL 8 33 34#define RTC_VAL 0x04 35 36#define RTC_TOP 0x08 37 38#define RTC_IER 0x10 39#define RTC_IER_TOPI 0 40 41#define RTC_IDR 0x14 42#define RTC_IDR_TOPI 0 43 44#define RTC_IMR 0x18 45#define RTC_IMR_TOPI 0 46 47#define RTC_ISR 0x1c 48#define RTC_ISR_TOPI 0 49 50#define RTC_ICR 0x20 51#define RTC_ICR_TOPI 0 52 53#define RTC_BIT(name) (1 << RTC_##name) 54#define RTC_BF(name, value) ((value) << RTC_##name) 55 56#define rtc_readl(dev, reg) \ 57 __raw_readl((dev)->regs + RTC_##reg) 58#define rtc_writel(dev, reg, value) \ 59 __raw_writel((value), (dev)->regs + RTC_##reg) 60 61struct rtc_at32ap700x { 62 struct rtc_device *rtc; 63 void __iomem *regs; 64 unsigned long alarm_time; 65 unsigned long irq; 66 /* Protect against concurrent register access. */ 67 spinlock_t lock; 68}; 69 70static int at32_rtc_readtime(struct device *dev, struct rtc_time *tm) 71{ 72 struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); 73 unsigned long now; 74 75 now = rtc_readl(rtc, VAL); 76 rtc_time_to_tm(now, tm); 77 78 return 0; 79} 80 81static int at32_rtc_settime(struct device *dev, struct rtc_time *tm) 82{ 83 struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); 84 unsigned long now; 85 int ret; 86 87 ret = rtc_tm_to_time(tm, &now); 88 if (ret == 0) 89 rtc_writel(rtc, VAL, now); 90 91 return ret; 92} 93 94static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) 95{ 96 struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); 97 98 spin_lock_irq(&rtc->lock); 99 rtc_time_to_tm(rtc->alarm_time, &alrm->time); 100 alrm->enabled = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0; 101 alrm->pending = rtc_readl(rtc, ISR) & RTC_BIT(ISR_TOPI) ? 1 : 0; 102 spin_unlock_irq(&rtc->lock); 103 104 return 0; 105} 106 107static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) 108{ 109 struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); 110 unsigned long rtc_unix_time; 111 unsigned long alarm_unix_time; 112 int ret; 113 114 rtc_unix_time = rtc_readl(rtc, VAL); 115 116 ret = rtc_tm_to_time(&alrm->time, &alarm_unix_time); 117 if (ret) 118 return ret; 119 120 if (alarm_unix_time < rtc_unix_time) 121 return -EINVAL; 122 123 spin_lock_irq(&rtc->lock); 124 rtc->alarm_time = alarm_unix_time; 125 rtc_writel(rtc, TOP, rtc->alarm_time); 126 if (alrm->enabled) 127 rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) 128 | RTC_BIT(CTRL_TOPEN)); 129 else 130 rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) 131 & ~RTC_BIT(CTRL_TOPEN)); 132 spin_unlock_irq(&rtc->lock); 133 134 return ret; 135} 136 137static int at32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 138{ 139 struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); 140 int ret = 0; 141 142 spin_lock_irq(&rtc->lock); 143 144 if (enabled) { 145 if (rtc_readl(rtc, VAL) > rtc->alarm_time) { 146 ret = -EINVAL; 147 goto out; 148 } 149 rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) 150 | RTC_BIT(CTRL_TOPEN)); 151 rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); 152 rtc_writel(rtc, IER, RTC_BIT(IER_TOPI)); 153 } else { 154 rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) 155 & ~RTC_BIT(CTRL_TOPEN)); 156 rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); 157 rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); 158 } 159out: 160 spin_unlock_irq(&rtc->lock); 161 162 return ret; 163} 164 165static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id) 166{ 167 struct rtc_at32ap700x *rtc = (struct rtc_at32ap700x *)dev_id; 168 unsigned long isr = rtc_readl(rtc, ISR); 169 unsigned long events = 0; 170 int ret = IRQ_NONE; 171 172 spin_lock(&rtc->lock); 173 174 if (isr & RTC_BIT(ISR_TOPI)) { 175 rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); 176 rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); 177 rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) 178 & ~RTC_BIT(CTRL_TOPEN)); 179 rtc_writel(rtc, VAL, rtc->alarm_time); 180 events = RTC_AF | RTC_IRQF; 181 rtc_update_irq(rtc->rtc, 1, events); 182 ret = IRQ_HANDLED; 183 } 184 185 spin_unlock(&rtc->lock); 186 187 return ret; 188} 189 190static struct rtc_class_ops at32_rtc_ops = { 191 .read_time = at32_rtc_readtime, 192 .set_time = at32_rtc_settime, 193 .read_alarm = at32_rtc_readalarm, 194 .set_alarm = at32_rtc_setalarm, 195 .alarm_irq_enable = at32_rtc_alarm_irq_enable, 196}; 197 198static int __init at32_rtc_probe(struct platform_device *pdev) 199{ 200 struct resource *regs; 201 struct rtc_at32ap700x *rtc; 202 int irq; 203 int ret; 204 205 rtc = devm_kzalloc(&pdev->dev, sizeof(struct rtc_at32ap700x), 206 GFP_KERNEL); 207 if (!rtc) 208 return -ENOMEM; 209 210 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 211 if (!regs) { 212 dev_dbg(&pdev->dev, "no mmio resource defined\n"); 213 return -ENXIO; 214 } 215 216 irq = platform_get_irq(pdev, 0); 217 if (irq <= 0) { 218 dev_dbg(&pdev->dev, "could not get irq\n"); 219 return -ENXIO; 220 } 221 222 rtc->irq = irq; 223 rtc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); 224 if (!rtc->regs) { 225 dev_dbg(&pdev->dev, "could not map I/O memory\n"); 226 return -ENOMEM; 227 } 228 spin_lock_init(&rtc->lock); 229 230 /* 231 * Maybe init RTC: count from zero at 1 Hz, disable wrap irq. 232 * 233 * Do not reset VAL register, as it can hold an old time 234 * from last JTAG reset. 235 */ 236 if (!(rtc_readl(rtc, CTRL) & RTC_BIT(CTRL_EN))) { 237 rtc_writel(rtc, CTRL, RTC_BIT(CTRL_PCLR)); 238 rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); 239 rtc_writel(rtc, CTRL, RTC_BF(CTRL_PSEL, 0xe) 240 | RTC_BIT(CTRL_EN)); 241 } 242 243 ret = devm_request_irq(&pdev->dev, irq, at32_rtc_interrupt, IRQF_SHARED, 244 "rtc", rtc); 245 if (ret) { 246 dev_dbg(&pdev->dev, "could not request irq %d\n", irq); 247 return ret; 248 } 249 250 platform_set_drvdata(pdev, rtc); 251 252 rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, 253 &at32_rtc_ops, THIS_MODULE); 254 if (IS_ERR(rtc->rtc)) { 255 dev_dbg(&pdev->dev, "could not register rtc device\n"); 256 return PTR_ERR(rtc->rtc); 257 } 258 259 device_init_wakeup(&pdev->dev, 1); 260 261 dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n", 262 (unsigned long)rtc->regs, rtc->irq); 263 264 return 0; 265} 266 267static int __exit at32_rtc_remove(struct platform_device *pdev) 268{ 269 device_init_wakeup(&pdev->dev, 0); 270 271 return 0; 272} 273 274MODULE_ALIAS("platform:at32ap700x_rtc"); 275 276static struct platform_driver at32_rtc_driver = { 277 .remove = __exit_p(at32_rtc_remove), 278 .driver = { 279 .name = "at32ap700x_rtc", 280 }, 281}; 282 283module_platform_driver_probe(at32_rtc_driver, at32_rtc_probe); 284 285MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); 286MODULE_DESCRIPTION("Real time clock for AVR32 AT32AP700x"); 287MODULE_LICENSE("GPL"); 288