]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/rtc/rtc-mpc5121.c
Merge branch 'for-linus/bugfixes' of git://xenbits.xensource.com/people/ianc/linux-2.6
[mv-sheeva.git] / drivers / rtc / rtc-mpc5121.c
1 /*
2  * Real-time clock driver for MPC5121
3  *
4  * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
5  * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/rtc.h>
15 #include <linux/of_device.h>
16 #include <linux/of_platform.h>
17 #include <linux/io.h>
18 #include <linux/slab.h>
19
20 struct mpc5121_rtc_regs {
21         u8 set_time;            /* RTC + 0x00 */
22         u8 hour_set;            /* RTC + 0x01 */
23         u8 minute_set;          /* RTC + 0x02 */
24         u8 second_set;          /* RTC + 0x03 */
25
26         u8 set_date;            /* RTC + 0x04 */
27         u8 month_set;           /* RTC + 0x05 */
28         u8 weekday_set;         /* RTC + 0x06 */
29         u8 date_set;            /* RTC + 0x07 */
30
31         u8 write_sw;            /* RTC + 0x08 */
32         u8 sw_set;              /* RTC + 0x09 */
33         u16 year_set;           /* RTC + 0x0a */
34
35         u8 alm_enable;          /* RTC + 0x0c */
36         u8 alm_hour_set;        /* RTC + 0x0d */
37         u8 alm_min_set;         /* RTC + 0x0e */
38         u8 int_enable;          /* RTC + 0x0f */
39
40         u8 reserved1;
41         u8 hour;                /* RTC + 0x11 */
42         u8 minute;              /* RTC + 0x12 */
43         u8 second;              /* RTC + 0x13 */
44
45         u8 month;               /* RTC + 0x14 */
46         u8 wday_mday;           /* RTC + 0x15 */
47         u16 year;               /* RTC + 0x16 */
48
49         u8 int_alm;             /* RTC + 0x18 */
50         u8 int_sw;              /* RTC + 0x19 */
51         u8 alm_status;          /* RTC + 0x1a */
52         u8 sw_minute;           /* RTC + 0x1b */
53
54         u8 bus_error_1;         /* RTC + 0x1c */
55         u8 int_day;             /* RTC + 0x1d */
56         u8 int_min;             /* RTC + 0x1e */
57         u8 int_sec;             /* RTC + 0x1f */
58
59         /*
60          * target_time:
61          *      intended to be used for hibernation but hibernation
62          *      does not work on silicon rev 1.5 so use it for non-volatile
63          *      storage of offset between the actual_time register and linux
64          *      time
65          */
66         u32 target_time;        /* RTC + 0x20 */
67         /*
68          * actual_time:
69          *      readonly time since VBAT_RTC was last connected
70          */
71         u32 actual_time;        /* RTC + 0x24 */
72         u32 keep_alive;         /* RTC + 0x28 */
73 };
74
75 struct mpc5121_rtc_data {
76         unsigned irq;
77         unsigned irq_periodic;
78         struct mpc5121_rtc_regs __iomem *regs;
79         struct rtc_device *rtc;
80         struct rtc_wkalrm wkalarm;
81 };
82
83 /*
84  * Update second/minute/hour registers.
85  *
86  * This is just so alarm will work.
87  */
88 static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs,
89                                    struct rtc_time *tm)
90 {
91         out_8(&regs->second_set, tm->tm_sec);
92         out_8(&regs->minute_set, tm->tm_min);
93         out_8(&regs->hour_set, tm->tm_hour);
94
95         /* set time sequence */
96         out_8(&regs->set_time, 0x1);
97         out_8(&regs->set_time, 0x3);
98         out_8(&regs->set_time, 0x1);
99         out_8(&regs->set_time, 0x0);
100 }
101
102 static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
103 {
104         struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
105         struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
106         unsigned long now;
107
108         /*
109          * linux time is actual_time plus the offset saved in target_time
110          */
111         now = in_be32(&regs->actual_time) + in_be32(&regs->target_time);
112
113         rtc_time_to_tm(now, tm);
114
115         /*
116          * update second minute hour registers
117          * so alarms will work
118          */
119         mpc5121_rtc_update_smh(regs, tm);
120
121         return rtc_valid_tm(tm);
122 }
123
124 static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
125 {
126         struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
127         struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
128         int ret;
129         unsigned long now;
130
131         /*
132          * The actual_time register is read only so we write the offset
133          * between it and linux time to the target_time register.
134          */
135         ret = rtc_tm_to_time(tm, &now);
136         if (ret == 0)
137                 out_be32(&regs->target_time, now - in_be32(&regs->actual_time));
138
139         /*
140          * update second minute hour registers
141          * so alarms will work
142          */
143         mpc5121_rtc_update_smh(regs, tm);
144
145         return 0;
146 }
147
148 static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
149 {
150         struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
151         struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
152
153         *alarm = rtc->wkalarm;
154
155         alarm->pending = in_8(&regs->alm_status);
156
157         return 0;
158 }
159
160 static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
161 {
162         struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
163         struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
164
165         /*
166          * the alarm has no seconds so deal with it
167          */
168         if (alarm->time.tm_sec) {
169                 alarm->time.tm_sec = 0;
170                 alarm->time.tm_min++;
171                 if (alarm->time.tm_min >= 60) {
172                         alarm->time.tm_min = 0;
173                         alarm->time.tm_hour++;
174                         if (alarm->time.tm_hour >= 24)
175                                 alarm->time.tm_hour = 0;
176                 }
177         }
178
179         alarm->time.tm_mday = -1;
180         alarm->time.tm_mon = -1;
181         alarm->time.tm_year = -1;
182
183         out_8(&regs->alm_min_set, alarm->time.tm_min);
184         out_8(&regs->alm_hour_set, alarm->time.tm_hour);
185
186         out_8(&regs->alm_enable, alarm->enabled);
187
188         rtc->wkalarm = *alarm;
189         return 0;
190 }
191
192 static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
193 {
194         struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
195         struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
196
197         if (in_8(&regs->int_alm)) {
198                 /* acknowledge and clear status */
199                 out_8(&regs->int_alm, 1);
200                 out_8(&regs->alm_status, 1);
201
202                 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
203                 return IRQ_HANDLED;
204         }
205
206         return IRQ_NONE;
207 }
208
209 static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
210 {
211         struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
212         struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
213
214         if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)) {
215                 /* acknowledge */
216                 out_8(&regs->int_sec, 1);
217
218                 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
219                 return IRQ_HANDLED;
220         }
221
222         return IRQ_NONE;
223 }
224
225 static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
226                                         unsigned int enabled)
227 {
228         struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
229         struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
230         int val;
231
232         if (enabled)
233                 val = 1;
234         else
235                 val = 0;
236
237         out_8(&regs->alm_enable, val);
238         rtc->wkalarm.enabled = val;
239
240         return 0;
241 }
242
243 static int mpc5121_rtc_update_irq_enable(struct device *dev,
244                                          unsigned int enabled)
245 {
246         struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
247         struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
248         int val;
249
250         val = in_8(&regs->int_enable);
251
252         if (enabled)
253                 val = (val & ~0x8) | 0x1;
254         else
255                 val &= ~0x1;
256
257         out_8(&regs->int_enable, val);
258
259         return 0;
260 }
261
262 static const struct rtc_class_ops mpc5121_rtc_ops = {
263         .read_time = mpc5121_rtc_read_time,
264         .set_time = mpc5121_rtc_set_time,
265         .read_alarm = mpc5121_rtc_read_alarm,
266         .set_alarm = mpc5121_rtc_set_alarm,
267         .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
268         .update_irq_enable = mpc5121_rtc_update_irq_enable,
269 };
270
271 static int __devinit mpc5121_rtc_probe(struct of_device *op,
272                                         const struct of_device_id *match)
273 {
274         struct mpc5121_rtc_data *rtc;
275         int err = 0;
276         u32 ka;
277
278         rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
279         if (!rtc)
280                 return -ENOMEM;
281
282         rtc->regs = of_iomap(op->dev.of_node, 0);
283         if (!rtc->regs) {
284                 dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
285                 err = -ENOSYS;
286                 goto out_free;
287         }
288
289         device_init_wakeup(&op->dev, 1);
290
291         dev_set_drvdata(&op->dev, rtc);
292
293         rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
294         err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
295                                                 "mpc5121-rtc", &op->dev);
296         if (err) {
297                 dev_err(&op->dev, "%s: could not request irq: %i\n",
298                                                         __func__, rtc->irq);
299                 goto out_dispose;
300         }
301
302         rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0);
303         err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
304                                 IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev);
305         if (err) {
306                 dev_err(&op->dev, "%s: could not request irq: %i\n",
307                                                 __func__, rtc->irq_periodic);
308                 goto out_dispose2;
309         }
310
311         ka = in_be32(&rtc->regs->keep_alive);
312         if (ka & 0x02) {
313                 dev_warn(&op->dev,
314                         "mpc5121-rtc: Battery or oscillator failure!\n");
315                 out_be32(&rtc->regs->keep_alive, ka);
316         }
317
318         rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
319                                         &mpc5121_rtc_ops, THIS_MODULE);
320         if (IS_ERR(rtc->rtc)) {
321                 err = PTR_ERR(rtc->rtc);
322                 goto out_free_irq;
323         }
324
325         return 0;
326
327 out_free_irq:
328         free_irq(rtc->irq_periodic, &op->dev);
329 out_dispose2:
330         irq_dispose_mapping(rtc->irq_periodic);
331         free_irq(rtc->irq, &op->dev);
332 out_dispose:
333         irq_dispose_mapping(rtc->irq);
334         iounmap(rtc->regs);
335 out_free:
336         kfree(rtc);
337
338         return err;
339 }
340
341 static int __devexit mpc5121_rtc_remove(struct of_device *op)
342 {
343         struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev);
344         struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
345
346         /* disable interrupt, so there are no nasty surprises */
347         out_8(&regs->alm_enable, 0);
348         out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
349
350         rtc_device_unregister(rtc->rtc);
351         iounmap(rtc->regs);
352         free_irq(rtc->irq, &op->dev);
353         free_irq(rtc->irq_periodic, &op->dev);
354         irq_dispose_mapping(rtc->irq);
355         irq_dispose_mapping(rtc->irq_periodic);
356         dev_set_drvdata(&op->dev, NULL);
357         kfree(rtc);
358
359         return 0;
360 }
361
362 static struct of_device_id mpc5121_rtc_match[] __devinitdata = {
363         { .compatible = "fsl,mpc5121-rtc", },
364         {},
365 };
366
367 static struct of_platform_driver mpc5121_rtc_driver = {
368         .driver = {
369                 .name = "mpc5121-rtc",
370                 .owner = THIS_MODULE,
371                 .of_match_table = mpc5121_rtc_match,
372         },
373         .probe = mpc5121_rtc_probe,
374         .remove = __devexit_p(mpc5121_rtc_remove),
375 };
376
377 static int __init mpc5121_rtc_init(void)
378 {
379         return of_register_platform_driver(&mpc5121_rtc_driver);
380 }
381 module_init(mpc5121_rtc_init);
382
383 static void __exit mpc5121_rtc_exit(void)
384 {
385         of_unregister_platform_driver(&mpc5121_rtc_driver);
386 }
387 module_exit(mpc5121_rtc_exit);
388
389 MODULE_LICENSE("GPL");
390 MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");