~ubuntu-branches/ubuntu/saucy/linux-n900/saucy

« back to all changes in this revision

Viewing changes to drivers/rtc/rtc-mv.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Poirier
  • Date: 2011-02-18 09:43:31 UTC
  • Revision ID: james.westby@ubuntu.com-20110218094331-eyubsja4f9k0yhmq
Tags: 2.6.35-1.1
Initial release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Driver for the RTC in Marvell SoCs.
 
3
 *
 
4
 * This file is licensed under the terms of the GNU General Public
 
5
 * License version 2.  This program is licensed "as is" without any
 
6
 * warranty of any kind, whether express or implied.
 
7
 */
 
8
 
 
9
#include <linux/init.h>
 
10
#include <linux/kernel.h>
 
11
#include <linux/rtc.h>
 
12
#include <linux/bcd.h>
 
13
#include <linux/io.h>
 
14
#include <linux/platform_device.h>
 
15
#include <linux/delay.h>
 
16
#include <linux/gfp.h>
 
17
 
 
18
 
 
19
#define RTC_TIME_REG_OFFS       0
 
20
#define RTC_SECONDS_OFFS        0
 
21
#define RTC_MINUTES_OFFS        8
 
22
#define RTC_HOURS_OFFS          16
 
23
#define RTC_WDAY_OFFS           24
 
24
#define RTC_HOURS_12H_MODE              (1 << 22) /* 12 hours mode */
 
25
 
 
26
#define RTC_DATE_REG_OFFS       4
 
27
#define RTC_MDAY_OFFS           0
 
28
#define RTC_MONTH_OFFS          8
 
29
#define RTC_YEAR_OFFS           16
 
30
 
 
31
#define RTC_ALARM_TIME_REG_OFFS 8
 
32
#define RTC_ALARM_DATE_REG_OFFS 0xc
 
33
#define RTC_ALARM_VALID         (1 << 7)
 
34
 
 
35
#define RTC_ALARM_INTERRUPT_MASK_REG_OFFS       0x10
 
36
#define RTC_ALARM_INTERRUPT_CASUE_REG_OFFS      0x14
 
37
 
 
38
struct rtc_plat_data {
 
39
        struct rtc_device *rtc;
 
40
        void __iomem *ioaddr;
 
41
        int             irq;
 
42
};
 
43
 
 
44
static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm)
 
45
{
 
46
        struct rtc_plat_data *pdata = dev_get_drvdata(dev);
 
47
        void __iomem *ioaddr = pdata->ioaddr;
 
48
        u32     rtc_reg;
 
49
 
 
50
        rtc_reg = (bin2bcd(tm->tm_sec) << RTC_SECONDS_OFFS) |
 
51
                (bin2bcd(tm->tm_min) << RTC_MINUTES_OFFS) |
 
52
                (bin2bcd(tm->tm_hour) << RTC_HOURS_OFFS) |
 
53
                (bin2bcd(tm->tm_wday) << RTC_WDAY_OFFS);
 
54
        writel(rtc_reg, ioaddr + RTC_TIME_REG_OFFS);
 
55
 
 
56
        rtc_reg = (bin2bcd(tm->tm_mday) << RTC_MDAY_OFFS) |
 
57
                (bin2bcd(tm->tm_mon + 1) << RTC_MONTH_OFFS) |
 
58
                (bin2bcd(tm->tm_year % 100) << RTC_YEAR_OFFS);
 
59
        writel(rtc_reg, ioaddr + RTC_DATE_REG_OFFS);
 
60
 
 
61
        return 0;
 
62
}
 
63
 
 
64
static int mv_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
65
{
 
66
        struct rtc_plat_data *pdata = dev_get_drvdata(dev);
 
67
        void __iomem *ioaddr = pdata->ioaddr;
 
68
        u32     rtc_time, rtc_date;
 
69
        unsigned int year, month, day, hour, minute, second, wday;
 
70
 
 
71
        rtc_time = readl(ioaddr + RTC_TIME_REG_OFFS);
 
72
        rtc_date = readl(ioaddr + RTC_DATE_REG_OFFS);
 
73
 
 
74
        second = rtc_time & 0x7f;
 
75
        minute = (rtc_time >> RTC_MINUTES_OFFS) & 0x7f;
 
76
        hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hours mode */
 
77
        wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7;
 
78
 
 
79
        day = rtc_date & 0x3f;
 
80
        month = (rtc_date >> RTC_MONTH_OFFS) & 0x3f;
 
81
        year = (rtc_date >> RTC_YEAR_OFFS) & 0xff;
 
82
 
 
83
        tm->tm_sec = bcd2bin(second);
 
84
        tm->tm_min = bcd2bin(minute);
 
85
        tm->tm_hour = bcd2bin(hour);
 
86
        tm->tm_mday = bcd2bin(day);
 
87
        tm->tm_wday = bcd2bin(wday);
 
88
        tm->tm_mon = bcd2bin(month) - 1;
 
89
        /* hw counts from year 2000, but tm_year is relative to 1900 */
 
90
        tm->tm_year = bcd2bin(year) + 100;
 
91
 
 
92
        return rtc_valid_tm(tm);
 
93
}
 
94
 
 
95
static int mv_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
96
{
 
97
        struct rtc_plat_data *pdata = dev_get_drvdata(dev);
 
98
        void __iomem *ioaddr = pdata->ioaddr;
 
99
        u32     rtc_time, rtc_date;
 
100
        unsigned int year, month, day, hour, minute, second, wday;
 
101
 
 
102
        rtc_time = readl(ioaddr + RTC_ALARM_TIME_REG_OFFS);
 
103
        rtc_date = readl(ioaddr + RTC_ALARM_DATE_REG_OFFS);
 
104
 
 
105
        second = rtc_time & 0x7f;
 
106
        minute = (rtc_time >> RTC_MINUTES_OFFS) & 0x7f;
 
107
        hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hours mode */
 
108
        wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7;
 
109
 
 
110
        day = rtc_date & 0x3f;
 
111
        month = (rtc_date >> RTC_MONTH_OFFS) & 0x3f;
 
112
        year = (rtc_date >> RTC_YEAR_OFFS) & 0xff;
 
113
 
 
114
        alm->time.tm_sec = bcd2bin(second);
 
115
        alm->time.tm_min = bcd2bin(minute);
 
116
        alm->time.tm_hour = bcd2bin(hour);
 
117
        alm->time.tm_mday = bcd2bin(day);
 
118
        alm->time.tm_wday = bcd2bin(wday);
 
119
        alm->time.tm_mon = bcd2bin(month) - 1;
 
120
        /* hw counts from year 2000, but tm_year is relative to 1900 */
 
121
        alm->time.tm_year = bcd2bin(year) + 100;
 
122
 
 
123
        if (rtc_valid_tm(&alm->time) < 0) {
 
124
                dev_err(dev, "retrieved alarm date/time is not valid.\n");
 
125
                rtc_time_to_tm(0, &alm->time);
 
126
        }
 
127
 
 
128
        alm->enabled = !!readl(ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
 
129
        return 0;
 
130
}
 
131
 
 
132
static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
133
{
 
134
        struct rtc_plat_data *pdata = dev_get_drvdata(dev);
 
135
        void __iomem *ioaddr = pdata->ioaddr;
 
136
        u32 rtc_reg = 0;
 
137
 
 
138
        if (alm->time.tm_sec >= 0)
 
139
                rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_sec))
 
140
                        << RTC_SECONDS_OFFS;
 
141
        if (alm->time.tm_min >= 0)
 
142
                rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_min))
 
143
                        << RTC_MINUTES_OFFS;
 
144
        if (alm->time.tm_hour >= 0)
 
145
                rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_hour))
 
146
                        << RTC_HOURS_OFFS;
 
147
 
 
148
        writel(rtc_reg, ioaddr + RTC_ALARM_TIME_REG_OFFS);
 
149
 
 
150
        if (alm->time.tm_mday >= 0)
 
151
                rtc_reg = (RTC_ALARM_VALID | bin2bcd(alm->time.tm_mday))
 
152
                        << RTC_MDAY_OFFS;
 
153
        else
 
154
                rtc_reg = 0;
 
155
 
 
156
        if (alm->time.tm_mon >= 0)
 
157
                rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_mon + 1))
 
158
                        << RTC_MONTH_OFFS;
 
159
 
 
160
        if (alm->time.tm_year >= 0)
 
161
                rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_year % 100))
 
162
                        << RTC_YEAR_OFFS;
 
163
 
 
164
        writel(rtc_reg, ioaddr + RTC_ALARM_DATE_REG_OFFS);
 
165
        writel(0, ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS);
 
166
        writel(alm->enabled ? 1 : 0,
 
167
               ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
 
168
 
 
169
        return 0;
 
170
}
 
171
 
 
172
static int mv_rtc_ioctl(struct device *dev, unsigned int cmd,
 
173
                        unsigned long arg)
 
174
{
 
175
        struct platform_device *pdev = to_platform_device(dev);
 
176
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
177
        void __iomem *ioaddr = pdata->ioaddr;
 
178
 
 
179
        if (pdata->irq < 0)
 
180
                return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
 
181
        switch (cmd) {
 
182
        case RTC_AIE_OFF:
 
183
                writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
 
184
                break;
 
185
        case RTC_AIE_ON:
 
186
                writel(1, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
 
187
                break;
 
188
        default:
 
189
                return -ENOIOCTLCMD;
 
190
        }
 
191
        return 0;
 
192
}
 
193
 
 
194
static irqreturn_t mv_rtc_interrupt(int irq, void *data)
 
195
{
 
196
        struct rtc_plat_data *pdata = data;
 
197
        void __iomem *ioaddr = pdata->ioaddr;
 
198
 
 
199
        /* alarm irq? */
 
200
        if (!readl(ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS))
 
201
                return IRQ_NONE;
 
202
 
 
203
        /* clear interrupt */
 
204
        writel(0, ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS);
 
205
        rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF);
 
206
        return IRQ_HANDLED;
 
207
}
 
208
 
 
209
static const struct rtc_class_ops mv_rtc_ops = {
 
210
        .read_time      = mv_rtc_read_time,
 
211
        .set_time       = mv_rtc_set_time,
 
212
};
 
213
 
 
214
static const struct rtc_class_ops mv_rtc_alarm_ops = {
 
215
        .read_time      = mv_rtc_read_time,
 
216
        .set_time       = mv_rtc_set_time,
 
217
        .read_alarm     = mv_rtc_read_alarm,
 
218
        .set_alarm      = mv_rtc_set_alarm,
 
219
        .ioctl          = mv_rtc_ioctl,
 
220
};
 
221
 
 
222
static int __devinit mv_rtc_probe(struct platform_device *pdev)
 
223
{
 
224
        struct resource *res;
 
225
        struct rtc_plat_data *pdata;
 
226
        resource_size_t size;
 
227
        u32 rtc_time;
 
228
 
 
229
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
230
        if (!res)
 
231
                return -ENODEV;
 
232
 
 
233
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 
234
        if (!pdata)
 
235
                return -ENOMEM;
 
236
 
 
237
        size = resource_size(res);
 
238
        if (!devm_request_mem_region(&pdev->dev, res->start, size,
 
239
                                     pdev->name))
 
240
                return -EBUSY;
 
241
 
 
242
        pdata->ioaddr = devm_ioremap(&pdev->dev, res->start, size);
 
243
        if (!pdata->ioaddr)
 
244
                return -ENOMEM;
 
245
 
 
246
        /* make sure the 24 hours mode is enabled */
 
247
        rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS);
 
248
        if (rtc_time & RTC_HOURS_12H_MODE) {
 
249
                dev_err(&pdev->dev, "24 Hours mode not supported.\n");
 
250
                return -EINVAL;
 
251
        }
 
252
 
 
253
        /* make sure it is actually functional */
 
254
        if (rtc_time == 0x01000000) {
 
255
                ssleep(1);
 
256
                rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS);
 
257
                if (rtc_time == 0x01000000) {
 
258
                        dev_err(&pdev->dev, "internal RTC not ticking\n");
 
259
                        return -ENODEV;
 
260
                }
 
261
        }
 
262
 
 
263
        pdata->irq = platform_get_irq(pdev, 0);
 
264
 
 
265
        platform_set_drvdata(pdev, pdata);
 
266
 
 
267
        if (pdata->irq >= 0) {
 
268
                device_init_wakeup(&pdev->dev, 1);
 
269
                pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,
 
270
                                                 &mv_rtc_alarm_ops,
 
271
                                                 THIS_MODULE);
 
272
        } else
 
273
                pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,
 
274
                                                 &mv_rtc_ops, THIS_MODULE);
 
275
        if (IS_ERR(pdata->rtc))
 
276
                return PTR_ERR(pdata->rtc);
 
277
 
 
278
        if (pdata->irq >= 0) {
 
279
                writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
 
280
                if (devm_request_irq(&pdev->dev, pdata->irq, mv_rtc_interrupt,
 
281
                                     IRQF_DISABLED | IRQF_SHARED,
 
282
                                     pdev->name, pdata) < 0) {
 
283
                        dev_warn(&pdev->dev, "interrupt not available.\n");
 
284
                        pdata->irq = -1;
 
285
                }
 
286
        }
 
287
 
 
288
        return 0;
 
289
}
 
290
 
 
291
static int __exit mv_rtc_remove(struct platform_device *pdev)
 
292
{
 
293
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
294
 
 
295
        if (pdata->irq >= 0)
 
296
                device_init_wakeup(&pdev->dev, 0);
 
297
 
 
298
        rtc_device_unregister(pdata->rtc);
 
299
        return 0;
 
300
}
 
301
 
 
302
static struct platform_driver mv_rtc_driver = {
 
303
        .remove         = __exit_p(mv_rtc_remove),
 
304
        .driver         = {
 
305
                .name   = "rtc-mv",
 
306
                .owner  = THIS_MODULE,
 
307
        },
 
308
};
 
309
 
 
310
static __init int mv_init(void)
 
311
{
 
312
        return platform_driver_probe(&mv_rtc_driver, mv_rtc_probe);
 
313
}
 
314
 
 
315
static __exit void mv_exit(void)
 
316
{
 
317
        platform_driver_unregister(&mv_rtc_driver);
 
318
}
 
319
 
 
320
module_init(mv_init);
 
321
module_exit(mv_exit);
 
322
 
 
323
MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>");
 
324
MODULE_DESCRIPTION("Marvell RTC driver");
 
325
MODULE_LICENSE("GPL");
 
326
MODULE_ALIAS("platform:rtc-mv");