Date:2010-04-24 12:12:37 (12 years 5 months ago)
Author:Lars C.
Commit:69bc9d192df1115ebdc4202f91a346b6019cd48f
Message:Add jz4740 rtc driver

Files: drivers/rtc/Kconfig (1 diff)
drivers/rtc/Makefile (1 diff)
drivers/rtc/rtc-jz4740.c (1 diff)

Change Details

drivers/rtc/Kconfig
488488      This driver can also be built as a module. If so, the module
489489      will be called rtc-efi.
490490
491config RTC_DRV_JZ4740
492    tristate "Ingenic JZ4720/JZ4740 SoC"
493    depends on RTC_CLASS
494    depends on SOC_JZ4740
495    help
496      If you say yes here you get support for the
497      Ingenic JZ4720/JZ4740 SoC RTC controller.
498
499      This driver can also be buillt as a module. If so, the module
500      will be called rtc-jz4740.
501
491502config RTC_DRV_STK17TA8
492503    tristate "Simtek STK17TA8"
493504    depends on RTC_CLASS
drivers/rtc/Makefile
4545obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
4646obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
4747obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
48obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
4849obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
4950obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
5051obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
drivers/rtc/rtc-jz4740.c
1/*
2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4720/JZ4740 SoC RTC driver
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <linux/rtc.h>
20#include <linux/slab.h>
21#include <linux/spinlock.h>
22
23#define JZ_REG_RTC_CTRL 0x00
24#define JZ_REG_RTC_SEC 0x04
25#define JZ_REG_RTC_SEC_ALARM 0x08
26#define JZ_REG_RTC_REGULATOR 0x0C
27#define JZ_REG_RTC_HIBERNATE 0x20
28#define JZ_REG_RTC_SCRATCHPAD 0x34
29
30#define JZ_RTC_CTRL_WRDY BIT(7)
31#define JZ_RTC_CTRL_1HZ BIT(6)
32#define JZ_RTC_CTRL_1HZ_IRQ BIT(5)
33#define JZ_RTC_CTRL_AF BIT(4)
34#define JZ_RTC_CTRL_AF_IRQ BIT(3)
35#define JZ_RTC_CTRL_AE BIT(2)
36#define JZ_RTC_CTRL_ENABLE BIT(0)
37
38struct jz4740_rtc {
39    struct resource *mem;
40    void __iomem *base;
41
42    struct rtc_device *rtc;
43
44    unsigned int irq;
45
46    spinlock_t lock;
47};
48
49static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
50{
51    return readl(rtc->base + reg);
52}
53
54static inline void jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
55{
56    uint32_t ctrl;
57    do {
58        ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
59    } while (!(ctrl & JZ_RTC_CTRL_WRDY));
60}
61
62
63static inline void jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg,
64                    uint32_t val)
65{
66    jz4740_rtc_wait_write_ready(rtc);
67    writel(val, rtc->base + reg);
68}
69
70static void jz4740_rtc_ctrl_set_bits(struct jz4740_rtc *rtc, uint32_t mask,
71                    uint32_t val)
72{
73    unsigned long flags;
74    uint32_t ctrl;
75
76    spin_lock_irqsave(&rtc->lock, flags);
77
78    ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
79
80    /* Don't clear interrupt flags by accident */
81    ctrl |= JZ_RTC_CTRL_1HZ | JZ_RTC_CTRL_AF;
82
83    ctrl &= ~mask;
84    ctrl |= val;
85
86    jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CTRL, ctrl);
87
88    spin_unlock_irqrestore(&rtc->lock, flags);
89}
90
91static inline struct jz4740_rtc *dev_to_rtc(struct device *dev)
92{
93    return dev_get_drvdata(dev);
94}
95
96static int jz4740_rtc_read_time(struct device *dev, struct rtc_time *time)
97{
98    struct jz4740_rtc *rtc = dev_to_rtc(dev);
99    uint32_t secs, secs2;
100
101    secs = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC);
102    secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC);
103
104    while (secs != secs2) {
105        secs = secs2;
106        secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC);
107    }
108
109    rtc_time_to_tm(secs, time);
110
111    return rtc_valid_tm(time);
112}
113
114static int jz4740_rtc_set_mmss(struct device *dev, unsigned long secs)
115{
116    struct jz4740_rtc *rtc = dev_to_rtc(dev);
117
118    if ((uint32_t)secs != secs)
119        return -EINVAL;
120
121    jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, secs);
122
123    return 0;
124}
125
126static int jz4740_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
127{
128    struct jz4740_rtc *rtc = dev_to_rtc(dev);
129    uint32_t secs, secs2;
130    uint32_t ctrl;
131
132    secs = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC_ALARM);
133    secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC_ALARM);
134
135    while (secs != secs2) {
136        secs = secs2;
137        secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC_ALARM);
138    }
139
140    ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
141
142    alrm->enabled = !!(ctrl & JZ_RTC_CTRL_AE);
143    alrm->pending = !!(ctrl & JZ_RTC_CTRL_AF);
144
145    rtc_time_to_tm(secs, &alrm->time);
146
147    return rtc_valid_tm(&alrm->time);
148}
149
150static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
151{
152    struct jz4740_rtc *rtc = dev_to_rtc(dev);
153    unsigned long secs;
154
155    rtc_tm_to_time(&alrm->time, &secs);
156
157    if ((uint32_t)secs != secs)
158        return -EINVAL;
159
160    jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC_ALARM, (uint32_t)secs);
161    jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AE,
162                    alrm->enabled ? JZ_RTC_CTRL_AE : 0);
163
164    return 0;
165}
166
167static int jz4740_rtc_update_irq_enable(struct device *dev, unsigned int enable)
168{
169    struct jz4740_rtc *rtc = dev_to_rtc(dev);
170    jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ_IRQ,
171                    enable ? JZ_RTC_CTRL_1HZ_IRQ : 0);
172    return 0;
173}
174
175
176static int jz4740_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
177{
178    struct jz4740_rtc *rtc = dev_to_rtc(dev);
179    jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AF_IRQ,
180                    enable ? JZ_RTC_CTRL_AF_IRQ : 0);
181    return 0;
182}
183
184static struct rtc_class_ops jz4740_rtc_ops = {
185    .read_time = jz4740_rtc_read_time,
186    .set_mmss = jz4740_rtc_set_mmss,
187    .read_alarm = jz4740_rtc_read_alarm,
188    .set_alarm = jz4740_rtc_set_alarm,
189    .update_irq_enable = jz4740_rtc_update_irq_enable,
190    .alarm_irq_enable = jz4740_rtc_alarm_irq_enable,
191};
192
193static irqreturn_t jz4740_rtc_irq(int irq, void *data)
194{
195    struct jz4740_rtc *rtc = data;
196    uint32_t ctrl;
197    unsigned long events = 0;
198    ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
199
200    if (ctrl & JZ_RTC_CTRL_1HZ)
201        events |= (RTC_UF | RTC_IRQF);
202
203    if (ctrl & JZ_RTC_CTRL_AF)
204        events |= (RTC_AF | RTC_IRQF);
205
206    rtc_update_irq(rtc->rtc, 1, events);
207
208    jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ | JZ_RTC_CTRL_AF, 0);
209
210    return IRQ_HANDLED;
211}
212
213void jz4740_rtc_poweroff(struct device *dev)
214{
215    struct jz4740_rtc *rtc = dev_get_drvdata(dev);
216    jz4740_rtc_reg_write(rtc, JZ_REG_RTC_HIBERNATE, 1);
217}
218EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff);
219
220static int __devinit jz4740_rtc_probe(struct platform_device *pdev)
221{
222    int ret;
223    struct jz4740_rtc *rtc;
224    uint32_t scratchpad;
225
226    rtc = kmalloc(sizeof(*rtc), GFP_KERNEL);
227
228    rtc->irq = platform_get_irq(pdev, 0);
229
230    if (rtc->irq < 0) {
231        ret = -ENOENT;
232        dev_err(&pdev->dev, "Failed to get platform irq\n");
233        goto err_free;
234    }
235
236    rtc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
237    if (!rtc->mem) {
238        ret = -ENOENT;
239        dev_err(&pdev->dev, "Failed to get platform mmio memory\n");
240        goto err_free;
241    }
242
243    rtc->mem = request_mem_region(rtc->mem->start, resource_size(rtc->mem),
244                    pdev->name);
245
246    if (!rtc->mem) {
247        ret = -EBUSY;
248        dev_err(&pdev->dev, "Failed to request mmio memory region\n");
249        goto err_free;
250    }
251
252    rtc->base = ioremap_nocache(rtc->mem->start, resource_size(rtc->mem));
253
254    if (!rtc->base) {
255        ret = -EBUSY;
256        dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
257        goto err_release_mem_region;
258    }
259
260    platform_set_drvdata(pdev, rtc);
261
262    rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &jz4740_rtc_ops,
263                    THIS_MODULE);
264
265    if (IS_ERR(rtc->rtc)) {
266        ret = PTR_ERR(rtc->rtc);
267        dev_err(&pdev->dev, "Failed to register rtc device: %d\n", ret);
268        goto err_iounmap;
269    }
270
271    ret = request_irq(rtc->irq, jz4740_rtc_irq, 0,
272                pdev->name, rtc);
273
274    if (ret) {
275        dev_err(&pdev->dev, "Failed to request rtc irq: %d\n", ret);
276        goto err_unregister_rtc;
277    }
278
279    scratchpad = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SCRATCHPAD);
280    if (scratchpad != 0x12345678) {
281        jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SCRATCHPAD, 0x12345678);
282        jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, 0);
283    }
284
285    return 0;
286
287err_unregister_rtc:
288    rtc_device_unregister(rtc->rtc);
289err_iounmap:
290    platform_set_drvdata(pdev, NULL);
291    iounmap(rtc->base);
292err_release_mem_region:
293    release_mem_region(rtc->mem->start, resource_size(rtc->mem));
294err_free:
295    kfree(rtc);
296
297    return ret;
298}
299
300static int __devexit jz4740_rtc_remove(struct platform_device *pdev)
301{
302    struct jz4740_rtc *rtc = platform_get_drvdata(pdev);
303
304    free_irq(rtc->irq, rtc);
305
306    rtc_device_unregister(rtc->rtc);
307
308    iounmap(rtc->base);
309    release_mem_region(rtc->mem->start, resource_size(rtc->mem));
310
311    kfree(rtc);
312
313    platform_set_drvdata(pdev, NULL);
314
315    return 0;
316}
317
318struct platform_driver jz4740_rtc_driver = {
319    .probe = jz4740_rtc_probe,
320    .remove = __devexit_p(jz4740_rtc_remove),
321    .driver = {
322        .name = "jz4740-rtc",
323        .owner = THIS_MODULE,
324    },
325};
326
327static int __init jz4740_rtc_init(void)
328{
329    return platform_driver_register(&jz4740_rtc_driver);
330}
331module_init(jz4740_rtc_init);
332
333static void __exit jz4740_rtc_exit(void)
334{
335    platform_driver_unregister(&jz4740_rtc_driver);
336}
337module_exit(jz4740_rtc_exit);
338
339MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
340MODULE_LICENSE("GPL");
341MODULE_DESCRIPTION("RTC driver for the JZ4720/JZ4740 SoC\n");
342MODULE_ALIAS("platform:jz4740-rtc");

Archive Download the corresponding diff file



interactive