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