rtc-stk17ta8.c revision 2fac6674ddf3164da42a76d62f8912073d629a30
1/*
2 * A RTC driver for the Simtek STK17TA8
3 *
4 * By Thomas Hommel <thomas.hommel@gefanuc.com>
5 *
6 * Based on the DS1553 driver from
7 * Atsushi Nemoto <anemo@mba.ocn.ne.jp>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/bcd.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/delay.h>
18#include <linux/jiffies.h>
19#include <linux/interrupt.h>
20#include <linux/rtc.h>
21#include <linux/platform_device.h>
22#include <linux/io.h>
23
24#define DRV_VERSION "0.1"
25
26#define RTC_REG_SIZE		0x20000
27#define RTC_OFFSET		0x1fff0
28
29#define RTC_FLAGS		(RTC_OFFSET + 0)
30#define RTC_CENTURY		(RTC_OFFSET + 1)
31#define RTC_SECONDS_ALARM	(RTC_OFFSET + 2)
32#define RTC_MINUTES_ALARM	(RTC_OFFSET + 3)
33#define RTC_HOURS_ALARM		(RTC_OFFSET + 4)
34#define RTC_DATE_ALARM		(RTC_OFFSET + 5)
35#define RTC_INTERRUPTS		(RTC_OFFSET + 6)
36#define RTC_WATCHDOG		(RTC_OFFSET + 7)
37#define RTC_CALIBRATION		(RTC_OFFSET + 8)
38#define RTC_SECONDS		(RTC_OFFSET + 9)
39#define RTC_MINUTES		(RTC_OFFSET + 10)
40#define RTC_HOURS		(RTC_OFFSET + 11)
41#define RTC_DAY			(RTC_OFFSET + 12)
42#define RTC_DATE		(RTC_OFFSET + 13)
43#define RTC_MONTH		(RTC_OFFSET + 14)
44#define RTC_YEAR		(RTC_OFFSET + 15)
45
46#define RTC_SECONDS_MASK	0x7f
47#define RTC_DAY_MASK		0x07
48#define RTC_CAL_MASK		0x3f
49
50/* Bits in the Calibration register */
51#define RTC_STOP		0x80
52
53/* Bits in the Flags register */
54#define RTC_FLAGS_AF		0x40
55#define RTC_FLAGS_PF		0x20
56#define RTC_WRITE		0x02
57#define RTC_READ		0x01
58
59/* Bits in the Interrupts register */
60#define RTC_INTS_AIE		0x40
61
62struct rtc_plat_data {
63	struct rtc_device *rtc;
64	void __iomem *ioaddr;
65	unsigned long baseaddr;
66	unsigned long last_jiffies;
67	int irq;
68	unsigned int irqen;
69	int alrm_sec;
70	int alrm_min;
71	int alrm_hour;
72	int alrm_mday;
73};
74
75static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
76{
77	struct platform_device *pdev = to_platform_device(dev);
78	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
79	void __iomem *ioaddr = pdata->ioaddr;
80	u8 flags;
81
82	flags = readb(pdata->ioaddr + RTC_FLAGS);
83	writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
84
85	writeb(bin2bcd(tm->tm_year % 100), ioaddr + RTC_YEAR);
86	writeb(bin2bcd(tm->tm_mon + 1), ioaddr + RTC_MONTH);
87	writeb(bin2bcd(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
88	writeb(bin2bcd(tm->tm_mday), ioaddr + RTC_DATE);
89	writeb(bin2bcd(tm->tm_hour), ioaddr + RTC_HOURS);
90	writeb(bin2bcd(tm->tm_min), ioaddr + RTC_MINUTES);
91	writeb(bin2bcd(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
92	writeb(bin2bcd((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY);
93
94	writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
95	return 0;
96}
97
98static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm)
99{
100	struct platform_device *pdev = to_platform_device(dev);
101	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
102	void __iomem *ioaddr = pdata->ioaddr;
103	unsigned int year, month, day, hour, minute, second, week;
104	unsigned int century;
105	u8 flags;
106
107	/* give enough time to update RTC in case of continuous read */
108	if (pdata->last_jiffies == jiffies)
109		msleep(1);
110	pdata->last_jiffies = jiffies;
111
112	flags = readb(pdata->ioaddr + RTC_FLAGS);
113	writeb(flags | RTC_READ, ioaddr + RTC_FLAGS);
114	second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
115	minute = readb(ioaddr + RTC_MINUTES);
116	hour = readb(ioaddr + RTC_HOURS);
117	day = readb(ioaddr + RTC_DATE);
118	week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
119	month = readb(ioaddr + RTC_MONTH);
120	year = readb(ioaddr + RTC_YEAR);
121	century = readb(ioaddr + RTC_CENTURY);
122	writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS);
123	tm->tm_sec = bcd2bin(second);
124	tm->tm_min = bcd2bin(minute);
125	tm->tm_hour = bcd2bin(hour);
126	tm->tm_mday = bcd2bin(day);
127	tm->tm_wday = bcd2bin(week);
128	tm->tm_mon = bcd2bin(month) - 1;
129	/* year is 1900 + tm->tm_year */
130	tm->tm_year = bcd2bin(year) + bcd2bin(century) * 100 - 1900;
131
132	if (rtc_valid_tm(tm) < 0) {
133		dev_err(dev, "retrieved date/time is not valid.\n");
134		rtc_time_to_tm(0, tm);
135	}
136	return 0;
137}
138
139static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
140{
141	void __iomem *ioaddr = pdata->ioaddr;
142	unsigned long irqflags;
143	u8 flags;
144
145	spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags);
146
147	flags = readb(ioaddr + RTC_FLAGS);
148	writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
149
150	writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
151	       0x80 : bin2bcd(pdata->alrm_mday),
152	       ioaddr + RTC_DATE_ALARM);
153	writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
154	       0x80 : bin2bcd(pdata->alrm_hour),
155	       ioaddr + RTC_HOURS_ALARM);
156	writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
157	       0x80 : bin2bcd(pdata->alrm_min),
158	       ioaddr + RTC_MINUTES_ALARM);
159	writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
160	       0x80 : bin2bcd(pdata->alrm_sec),
161	       ioaddr + RTC_SECONDS_ALARM);
162	writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
163	readb(ioaddr + RTC_FLAGS);	/* clear interrupts */
164	writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
165	spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags);
166}
167
168static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
169{
170	struct platform_device *pdev = to_platform_device(dev);
171	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
172
173	if (pdata->irq <= 0)
174		return -EINVAL;
175	pdata->alrm_mday = alrm->time.tm_mday;
176	pdata->alrm_hour = alrm->time.tm_hour;
177	pdata->alrm_min = alrm->time.tm_min;
178	pdata->alrm_sec = alrm->time.tm_sec;
179	if (alrm->enabled)
180		pdata->irqen |= RTC_AF;
181	stk17ta8_rtc_update_alarm(pdata);
182	return 0;
183}
184
185static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
186{
187	struct platform_device *pdev = to_platform_device(dev);
188	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
189
190	if (pdata->irq <= 0)
191		return -EINVAL;
192	alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
193	alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
194	alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
195	alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
196	alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
197	return 0;
198}
199
200static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
201{
202	struct platform_device *pdev = dev_id;
203	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
204	void __iomem *ioaddr = pdata->ioaddr;
205	unsigned long events = RTC_IRQF;
206
207	/* read and clear interrupt */
208	if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
209		return IRQ_NONE;
210	if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
211		events |= RTC_UF;
212	else
213		events |= RTC_AF;
214	rtc_update_irq(pdata->rtc, 1, events);
215	return IRQ_HANDLED;
216}
217
218static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd,
219			    unsigned long arg)
220{
221	struct platform_device *pdev = to_platform_device(dev);
222	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
223
224	if (pdata->irq <= 0)
225		return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
226	switch (cmd) {
227	case RTC_AIE_OFF:
228		pdata->irqen &= ~RTC_AF;
229		stk17ta8_rtc_update_alarm(pdata);
230		break;
231	case RTC_AIE_ON:
232		pdata->irqen |= RTC_AF;
233		stk17ta8_rtc_update_alarm(pdata);
234		break;
235	default:
236		return -ENOIOCTLCMD;
237	}
238	return 0;
239}
240
241static const struct rtc_class_ops stk17ta8_rtc_ops = {
242	.read_time	= stk17ta8_rtc_read_time,
243	.set_time	= stk17ta8_rtc_set_time,
244	.read_alarm	= stk17ta8_rtc_read_alarm,
245	.set_alarm	= stk17ta8_rtc_set_alarm,
246	.ioctl		= stk17ta8_rtc_ioctl,
247};
248
249static ssize_t stk17ta8_nvram_read(struct kobject *kobj,
250				 struct bin_attribute *attr, char *buf,
251				 loff_t pos, size_t size)
252{
253	struct platform_device *pdev =
254		to_platform_device(container_of(kobj, struct device, kobj));
255	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
256	void __iomem *ioaddr = pdata->ioaddr;
257	ssize_t count;
258
259	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
260		*buf++ = readb(ioaddr + pos++);
261	return count;
262}
263
264static ssize_t stk17ta8_nvram_write(struct kobject *kobj,
265				  struct bin_attribute *attr, char *buf,
266				  loff_t pos, size_t size)
267{
268	struct platform_device *pdev =
269		to_platform_device(container_of(kobj, struct device, kobj));
270	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
271	void __iomem *ioaddr = pdata->ioaddr;
272	ssize_t count;
273
274	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
275		writeb(*buf++, ioaddr + pos++);
276	return count;
277}
278
279static struct bin_attribute stk17ta8_nvram_attr = {
280	.attr = {
281		.name = "nvram",
282		.mode = S_IRUGO | S_IWUSR,
283	},
284	.size = RTC_OFFSET,
285	.read = stk17ta8_nvram_read,
286	.write = stk17ta8_nvram_write,
287};
288
289static int __init stk17ta8_rtc_probe(struct platform_device *pdev)
290{
291	struct rtc_device *rtc;
292	struct resource *res;
293	unsigned int cal;
294	unsigned int flags;
295	struct rtc_plat_data *pdata;
296	void __iomem *ioaddr = NULL;
297	int ret = 0;
298
299	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
300	if (!res)
301		return -ENODEV;
302
303	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
304	if (!pdata)
305		return -ENOMEM;
306	if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
307		ret = -EBUSY;
308		goto out;
309	}
310	pdata->baseaddr = res->start;
311	ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
312	if (!ioaddr) {
313		ret = -ENOMEM;
314		goto out;
315	}
316	pdata->ioaddr = ioaddr;
317	pdata->irq = platform_get_irq(pdev, 0);
318
319	/* turn RTC on if it was not on */
320	cal = readb(ioaddr + RTC_CALIBRATION);
321	if (cal & RTC_STOP) {
322		cal &= RTC_CAL_MASK;
323		flags = readb(ioaddr + RTC_FLAGS);
324		writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
325		writeb(cal, ioaddr + RTC_CALIBRATION);
326		writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
327	}
328	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)
329		dev_warn(&pdev->dev, "voltage-low detected.\n");
330
331	if (pdata->irq > 0) {
332		writeb(0, ioaddr + RTC_INTERRUPTS);
333		if (request_irq(pdata->irq, stk17ta8_rtc_interrupt,
334				IRQF_DISABLED | IRQF_SHARED,
335				pdev->name, pdev) < 0) {
336			dev_warn(&pdev->dev, "interrupt not available.\n");
337			pdata->irq = 0;
338		}
339	}
340
341	rtc = rtc_device_register(pdev->name, &pdev->dev,
342				  &stk17ta8_rtc_ops, THIS_MODULE);
343	if (IS_ERR(rtc)) {
344		ret = PTR_ERR(rtc);
345		goto out;
346	}
347	pdata->rtc = rtc;
348	pdata->last_jiffies = jiffies;
349	platform_set_drvdata(pdev, pdata);
350	ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
351	if (ret)
352		goto out;
353	return 0;
354 out:
355	if (pdata->rtc)
356		rtc_device_unregister(pdata->rtc);
357	if (pdata->irq > 0)
358		free_irq(pdata->irq, pdev);
359	if (ioaddr)
360		iounmap(ioaddr);
361	if (pdata->baseaddr)
362		release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
363	kfree(pdata);
364	return ret;
365}
366
367static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)
368{
369	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
370
371	sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
372	rtc_device_unregister(pdata->rtc);
373	if (pdata->irq > 0) {
374		writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
375		free_irq(pdata->irq, pdev);
376	}
377	iounmap(pdata->ioaddr);
378	release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
379	kfree(pdata);
380	return 0;
381}
382
383/* work with hotplug and coldplug */
384MODULE_ALIAS("platform:stk17ta8");
385
386static struct platform_driver stk17ta8_rtc_driver = {
387	.probe		= stk17ta8_rtc_probe,
388	.remove		= __devexit_p(stk17ta8_rtc_remove),
389	.driver		= {
390		.name	= "stk17ta8",
391		.owner	= THIS_MODULE,
392	},
393};
394
395static __init int stk17ta8_init(void)
396{
397	return platform_driver_register(&stk17ta8_rtc_driver);
398}
399
400static __exit void stk17ta8_exit(void)
401{
402	return platform_driver_unregister(&stk17ta8_rtc_driver);
403}
404
405module_init(stk17ta8_init);
406module_exit(stk17ta8_exit);
407
408MODULE_AUTHOR("Thomas Hommel <thomas.hommel@gefanuc.com>");
409MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
410MODULE_LICENSE("GPL");
411MODULE_VERSION(DRV_VERSION);
412