Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7-rc7 319 lines 7.5 kB view raw
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 = kzalloc(sizeof(struct rtc_at32ap700x), GFP_KERNEL); 206 if (!rtc) { 207 dev_dbg(&pdev->dev, "out of memory\n"); 208 return -ENOMEM; 209 } 210 211 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 212 if (!regs) { 213 dev_dbg(&pdev->dev, "no mmio resource defined\n"); 214 ret = -ENXIO; 215 goto out; 216 } 217 218 irq = platform_get_irq(pdev, 0); 219 if (irq <= 0) { 220 dev_dbg(&pdev->dev, "could not get irq\n"); 221 ret = -ENXIO; 222 goto out; 223 } 224 225 rtc->irq = irq; 226 rtc->regs = ioremap(regs->start, resource_size(regs)); 227 if (!rtc->regs) { 228 ret = -ENOMEM; 229 dev_dbg(&pdev->dev, "could not map I/O memory\n"); 230 goto out; 231 } 232 spin_lock_init(&rtc->lock); 233 234 /* 235 * Maybe init RTC: count from zero at 1 Hz, disable wrap irq. 236 * 237 * Do not reset VAL register, as it can hold an old time 238 * from last JTAG reset. 239 */ 240 if (!(rtc_readl(rtc, CTRL) & RTC_BIT(CTRL_EN))) { 241 rtc_writel(rtc, CTRL, RTC_BIT(CTRL_PCLR)); 242 rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); 243 rtc_writel(rtc, CTRL, RTC_BF(CTRL_PSEL, 0xe) 244 | RTC_BIT(CTRL_EN)); 245 } 246 247 ret = request_irq(irq, at32_rtc_interrupt, IRQF_SHARED, "rtc", rtc); 248 if (ret) { 249 dev_dbg(&pdev->dev, "could not request irq %d\n", irq); 250 goto out_iounmap; 251 } 252 253 platform_set_drvdata(pdev, rtc); 254 255 rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, 256 &at32_rtc_ops, THIS_MODULE); 257 if (IS_ERR(rtc->rtc)) { 258 dev_dbg(&pdev->dev, "could not register rtc device\n"); 259 ret = PTR_ERR(rtc->rtc); 260 goto out_free_irq; 261 } 262 263 device_init_wakeup(&pdev->dev, 1); 264 265 dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n", 266 (unsigned long)rtc->regs, rtc->irq); 267 268 return 0; 269 270out_free_irq: 271 platform_set_drvdata(pdev, NULL); 272 free_irq(irq, rtc); 273out_iounmap: 274 iounmap(rtc->regs); 275out: 276 kfree(rtc); 277 return ret; 278} 279 280static int __exit at32_rtc_remove(struct platform_device *pdev) 281{ 282 struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev); 283 284 device_init_wakeup(&pdev->dev, 0); 285 286 free_irq(rtc->irq, rtc); 287 iounmap(rtc->regs); 288 rtc_device_unregister(rtc->rtc); 289 kfree(rtc); 290 platform_set_drvdata(pdev, NULL); 291 292 return 0; 293} 294 295MODULE_ALIAS("platform:at32ap700x_rtc"); 296 297static struct platform_driver at32_rtc_driver = { 298 .remove = __exit_p(at32_rtc_remove), 299 .driver = { 300 .name = "at32ap700x_rtc", 301 .owner = THIS_MODULE, 302 }, 303}; 304 305static int __init at32_rtc_init(void) 306{ 307 return platform_driver_probe(&at32_rtc_driver, at32_rtc_probe); 308} 309module_init(at32_rtc_init); 310 311static void __exit at32_rtc_exit(void) 312{ 313 platform_driver_unregister(&at32_rtc_driver); 314} 315module_exit(at32_rtc_exit); 316 317MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); 318MODULE_DESCRIPTION("Real time clock for AVR32 AT32AP700x"); 319MODULE_LICENSE("GPL");