diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 29 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 3 | ||||
-rw-r--r-- | drivers/rtc/rtc-cmos.c | 6 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds3232.c | 326 | ||||
-rw-r--r-- | drivers/rtc/rtc-fm3130.c | 181 | ||||
-rw-r--r-- | drivers/rtc/rtc-imxdi.c | 519 | ||||
-rw-r--r-- | drivers/rtc/rtc-isl12022.c | 327 | ||||
-rw-r--r-- | drivers/rtc/rtc-m41t80.c | 4 | ||||
-rw-r--r-- | drivers/rtc/rtc-m48t59.c | 5 | ||||
-rw-r--r-- | drivers/rtc/rtc-m48t86.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-max6900.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-mxc.c | 6 | ||||
-rw-r--r-- | drivers/rtc/rtc-nuc900.c | 64 | ||||
-rw-r--r-- | drivers/rtc/rtc-pcf8563.c | 8 | ||||
-rw-r--r-- | drivers/rtc/rtc-pl031.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-pxa.c | 42 | ||||
-rw-r--r-- | drivers/rtc/rtc-rp5c01.c | 89 |
17 files changed, 1484 insertions, 130 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9238c8f40f03..48ca7132cc05 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -166,6 +166,16 @@ config RTC_DRV_DS1672 | |||
166 | This driver can also be built as a module. If so, the module | 166 | This driver can also be built as a module. If so, the module |
167 | will be called rtc-ds1672. | 167 | will be called rtc-ds1672. |
168 | 168 | ||
169 | config RTC_DRV_DS3232 | ||
170 | tristate "Dallas/Maxim DS3232" | ||
171 | depends on RTC_CLASS && I2C | ||
172 | help | ||
173 | If you say yes here you get support for Dallas Semiconductor | ||
174 | DS3232 real-time clock chips. | ||
175 | |||
176 | This driver can also be built as a module. If so, the module | ||
177 | will be called rtc-ds3232. | ||
178 | |||
169 | config RTC_DRV_MAX6900 | 179 | config RTC_DRV_MAX6900 |
170 | tristate "Maxim MAX6900" | 180 | tristate "Maxim MAX6900" |
171 | help | 181 | help |
@@ -203,6 +213,15 @@ config RTC_DRV_ISL1208 | |||
203 | This driver can also be built as a module. If so, the module | 213 | This driver can also be built as a module. If so, the module |
204 | will be called rtc-isl1208. | 214 | will be called rtc-isl1208. |
205 | 215 | ||
216 | config RTC_DRV_ISL12022 | ||
217 | tristate "Intersil ISL12022" | ||
218 | help | ||
219 | If you say yes here you get support for the | ||
220 | Intersil ISL12022 RTC chip. | ||
221 | |||
222 | This driver can also be built as a module. If so, the module | ||
223 | will be called rtc-isl12022. | ||
224 | |||
206 | config RTC_DRV_X1205 | 225 | config RTC_DRV_X1205 |
207 | tristate "Xicor/Intersil X1205" | 226 | tristate "Xicor/Intersil X1205" |
208 | help | 227 | help |
@@ -537,6 +556,16 @@ config RTC_DRV_MSM6242 | |||
537 | This driver can also be built as a module. If so, the module | 556 | This driver can also be built as a module. If so, the module |
538 | will be called rtc-msm6242. | 557 | will be called rtc-msm6242. |
539 | 558 | ||
559 | config RTC_DRV_IMXDI | ||
560 | tristate "Freescale IMX DryIce Real Time Clock" | ||
561 | depends on ARCH_MX25 | ||
562 | depends on RTC_CLASS | ||
563 | help | ||
564 | Support for Freescale IMX DryIce RTC | ||
565 | |||
566 | This driver can also be built as a module, if so, the module | ||
567 | will be called "rtc-imxdi". | ||
568 | |||
540 | config RTC_MXC | 569 | config RTC_MXC |
541 | tristate "Freescale MXC Real Time Clock" | 570 | tristate "Freescale MXC Real Time Clock" |
542 | depends on ARCH_MXC | 571 | depends on ARCH_MXC |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index fedf9bb36593..0f207b3b5833 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -41,12 +41,15 @@ obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o | |||
41 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o | 41 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o |
42 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o | 42 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o |
43 | obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o | 43 | obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o |
44 | obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o | ||
44 | obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o | 45 | obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o |
45 | obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o | 46 | obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o |
46 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | 47 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o |
47 | obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o | 48 | obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o |
48 | obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o | 49 | obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o |
50 | obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o | ||
49 | obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o | 51 | obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o |
52 | obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o | ||
50 | obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o | 53 | obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o |
51 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o | 54 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o |
52 | obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o | 55 | obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o |
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 11b8ea29d2b7..5856167a0c90 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c | |||
@@ -970,7 +970,6 @@ static inline int cmos_poweroff(struct device *dev) | |||
970 | 970 | ||
971 | #include <linux/acpi.h> | 971 | #include <linux/acpi.h> |
972 | 972 | ||
973 | #ifdef CONFIG_PM | ||
974 | static u32 rtc_handler(void *context) | 973 | static u32 rtc_handler(void *context) |
975 | { | 974 | { |
976 | acpi_clear_event(ACPI_EVENT_RTC); | 975 | acpi_clear_event(ACPI_EVENT_RTC); |
@@ -999,11 +998,6 @@ static void rtc_wake_off(struct device *dev) | |||
999 | { | 998 | { |
1000 | acpi_disable_event(ACPI_EVENT_RTC, 0); | 999 | acpi_disable_event(ACPI_EVENT_RTC, 0); |
1001 | } | 1000 | } |
1002 | #else | ||
1003 | #define rtc_wake_setup() do{}while(0) | ||
1004 | #define rtc_wake_on NULL | ||
1005 | #define rtc_wake_off NULL | ||
1006 | #endif | ||
1007 | 1001 | ||
1008 | /* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find | 1002 | /* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find |
1009 | * its device node and pass extra config data. This helps its driver use | 1003 | * its device node and pass extra config data. This helps its driver use |
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c new file mode 100644 index 000000000000..9daed8db83d3 --- /dev/null +++ b/drivers/rtc/rtc-ds3232.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C | ||
3 | * | ||
4 | * Copyright (C) 2009-2010 Freescale Semiconductor. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | /* | ||
12 | * It would be more efficient to use i2c msgs/i2c_transfer directly but, as | ||
13 | * recommened in .../Documentation/i2c/writing-clients section | ||
14 | * "Sending and receiving", using SMBus level communication is preferred. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/rtc.h> | ||
22 | #include <linux/bcd.h> | ||
23 | #include <linux/workqueue.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #define DS3232_REG_SECONDS 0x00 | ||
27 | #define DS3232_REG_MINUTES 0x01 | ||
28 | #define DS3232_REG_HOURS 0x02 | ||
29 | #define DS3232_REG_AMPM 0x02 | ||
30 | #define DS3232_REG_DAY 0x03 | ||
31 | #define DS3232_REG_DATE 0x04 | ||
32 | #define DS3232_REG_MONTH 0x05 | ||
33 | #define DS3232_REG_CENTURY 0x05 | ||
34 | #define DS3232_REG_YEAR 0x06 | ||
35 | #define DS3232_REG_ALARM1 0x07 /* Alarm 1 BASE */ | ||
36 | #define DS3232_REG_ALARM2 0x0B /* Alarm 2 BASE */ | ||
37 | #define DS3232_REG_CR 0x0E /* Control register */ | ||
38 | # define DS3232_REG_CR_nEOSC 0x80 | ||
39 | # define DS3232_REG_CR_INTCN 0x04 | ||
40 | # define DS3232_REG_CR_A2IE 0x02 | ||
41 | # define DS3232_REG_CR_A1IE 0x01 | ||
42 | |||
43 | #define DS3232_REG_SR 0x0F /* control/status register */ | ||
44 | # define DS3232_REG_SR_OSF 0x80 | ||
45 | # define DS3232_REG_SR_BSY 0x04 | ||
46 | # define DS3232_REG_SR_A2F 0x02 | ||
47 | # define DS3232_REG_SR_A1F 0x01 | ||
48 | |||
49 | struct ds3232 { | ||
50 | struct i2c_client *client; | ||
51 | struct rtc_device *rtc; | ||
52 | struct work_struct work; | ||
53 | |||
54 | /* The mutex protects alarm operations, and prevents a race | ||
55 | * between the enable_irq() in the workqueue and the free_irq() | ||
56 | * in the remove function. | ||
57 | */ | ||
58 | struct mutex mutex; | ||
59 | int exiting; | ||
60 | }; | ||
61 | |||
62 | static struct i2c_driver ds3232_driver; | ||
63 | |||
64 | static int ds3232_check_rtc_status(struct i2c_client *client) | ||
65 | { | ||
66 | int ret = 0; | ||
67 | int control, stat; | ||
68 | |||
69 | stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR); | ||
70 | if (stat < 0) | ||
71 | return stat; | ||
72 | |||
73 | if (stat & DS3232_REG_SR_OSF) | ||
74 | dev_warn(&client->dev, | ||
75 | "oscillator discontinuity flagged, " | ||
76 | "time unreliable\n"); | ||
77 | |||
78 | stat &= ~(DS3232_REG_SR_OSF | DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); | ||
79 | |||
80 | ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | |||
84 | /* If the alarm is pending, clear it before requesting | ||
85 | * the interrupt, so an interrupt event isn't reported | ||
86 | * before everything is initialized. | ||
87 | */ | ||
88 | |||
89 | control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); | ||
90 | if (control < 0) | ||
91 | return control; | ||
92 | |||
93 | control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); | ||
94 | control |= DS3232_REG_CR_INTCN; | ||
95 | |||
96 | return i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); | ||
97 | } | ||
98 | |||
99 | static int ds3232_read_time(struct device *dev, struct rtc_time *time) | ||
100 | { | ||
101 | struct i2c_client *client = to_i2c_client(dev); | ||
102 | int ret; | ||
103 | u8 buf[7]; | ||
104 | unsigned int year, month, day, hour, minute, second; | ||
105 | unsigned int week, twelve_hr, am_pm; | ||
106 | unsigned int century, add_century = 0; | ||
107 | |||
108 | ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_SECONDS, 7, buf); | ||
109 | |||
110 | if (ret < 0) | ||
111 | return ret; | ||
112 | if (ret < 7) | ||
113 | return -EIO; | ||
114 | |||
115 | second = buf[0]; | ||
116 | minute = buf[1]; | ||
117 | hour = buf[2]; | ||
118 | week = buf[3]; | ||
119 | day = buf[4]; | ||
120 | month = buf[5]; | ||
121 | year = buf[6]; | ||
122 | |||
123 | /* Extract additional information for AM/PM and century */ | ||
124 | |||
125 | twelve_hr = hour & 0x40; | ||
126 | am_pm = hour & 0x20; | ||
127 | century = month & 0x80; | ||
128 | |||
129 | /* Write to rtc_time structure */ | ||
130 | |||
131 | time->tm_sec = bcd2bin(second); | ||
132 | time->tm_min = bcd2bin(minute); | ||
133 | if (twelve_hr) { | ||
134 | /* Convert to 24 hr */ | ||
135 | if (am_pm) | ||
136 | time->tm_hour = bcd2bin(hour & 0x1F) + 12; | ||
137 | else | ||
138 | time->tm_hour = bcd2bin(hour & 0x1F); | ||
139 | } else { | ||
140 | time->tm_hour = bcd2bin(hour); | ||
141 | } | ||
142 | |||
143 | time->tm_wday = bcd2bin(week); | ||
144 | time->tm_mday = bcd2bin(day); | ||
145 | time->tm_mon = bcd2bin(month & 0x7F); | ||
146 | if (century) | ||
147 | add_century = 100; | ||
148 | |||
149 | time->tm_year = bcd2bin(year) + add_century; | ||
150 | |||
151 | return rtc_valid_tm(time); | ||
152 | } | ||
153 | |||
154 | static int ds3232_set_time(struct device *dev, struct rtc_time *time) | ||
155 | { | ||
156 | struct i2c_client *client = to_i2c_client(dev); | ||
157 | u8 buf[7]; | ||
158 | |||
159 | /* Extract time from rtc_time and load into ds3232*/ | ||
160 | |||
161 | buf[0] = bin2bcd(time->tm_sec); | ||
162 | buf[1] = bin2bcd(time->tm_min); | ||
163 | buf[2] = bin2bcd(time->tm_hour); | ||
164 | buf[3] = bin2bcd(time->tm_wday); /* Day of the week */ | ||
165 | buf[4] = bin2bcd(time->tm_mday); /* Date */ | ||
166 | buf[5] = bin2bcd(time->tm_mon); | ||
167 | if (time->tm_year >= 100) { | ||
168 | buf[5] |= 0x80; | ||
169 | buf[6] = bin2bcd(time->tm_year - 100); | ||
170 | } else { | ||
171 | buf[6] = bin2bcd(time->tm_year); | ||
172 | } | ||
173 | |||
174 | return i2c_smbus_write_i2c_block_data(client, | ||
175 | DS3232_REG_SECONDS, 7, buf); | ||
176 | } | ||
177 | |||
178 | static irqreturn_t ds3232_irq(int irq, void *dev_id) | ||
179 | { | ||
180 | struct i2c_client *client = dev_id; | ||
181 | struct ds3232 *ds3232 = i2c_get_clientdata(client); | ||
182 | |||
183 | disable_irq_nosync(irq); | ||
184 | schedule_work(&ds3232->work); | ||
185 | return IRQ_HANDLED; | ||
186 | } | ||
187 | |||
188 | static void ds3232_work(struct work_struct *work) | ||
189 | { | ||
190 | struct ds3232 *ds3232 = container_of(work, struct ds3232, work); | ||
191 | struct i2c_client *client = ds3232->client; | ||
192 | int stat, control; | ||
193 | |||
194 | mutex_lock(&ds3232->mutex); | ||
195 | |||
196 | stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR); | ||
197 | if (stat < 0) | ||
198 | goto unlock; | ||
199 | |||
200 | if (stat & DS3232_REG_SR_A1F) { | ||
201 | control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); | ||
202 | if (control < 0) | ||
203 | goto out; | ||
204 | /* disable alarm1 interrupt */ | ||
205 | control &= ~(DS3232_REG_CR_A1IE); | ||
206 | i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); | ||
207 | |||
208 | /* clear the alarm pend flag */ | ||
209 | stat &= ~DS3232_REG_SR_A1F; | ||
210 | i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); | ||
211 | |||
212 | rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); | ||
213 | } | ||
214 | |||
215 | out: | ||
216 | if (!ds3232->exiting) | ||
217 | enable_irq(client->irq); | ||
218 | unlock: | ||
219 | mutex_unlock(&ds3232->mutex); | ||
220 | } | ||
221 | |||
222 | static const struct rtc_class_ops ds3232_rtc_ops = { | ||
223 | .read_time = ds3232_read_time, | ||
224 | .set_time = ds3232_set_time, | ||
225 | }; | ||
226 | |||
227 | static int __devinit ds3232_probe(struct i2c_client *client, | ||
228 | const struct i2c_device_id *id) | ||
229 | { | ||
230 | struct ds3232 *ds3232; | ||
231 | int ret; | ||
232 | |||
233 | ds3232 = kzalloc(sizeof(struct ds3232), GFP_KERNEL); | ||
234 | if (!ds3232) | ||
235 | return -ENOMEM; | ||
236 | |||
237 | ds3232->client = client; | ||
238 | i2c_set_clientdata(client, ds3232); | ||
239 | |||
240 | INIT_WORK(&ds3232->work, ds3232_work); | ||
241 | mutex_init(&ds3232->mutex); | ||
242 | |||
243 | ret = ds3232_check_rtc_status(client); | ||
244 | if (ret) | ||
245 | goto out_free; | ||
246 | |||
247 | ds3232->rtc = rtc_device_register(client->name, &client->dev, | ||
248 | &ds3232_rtc_ops, THIS_MODULE); | ||
249 | if (IS_ERR(ds3232->rtc)) { | ||
250 | ret = PTR_ERR(ds3232->rtc); | ||
251 | dev_err(&client->dev, "unable to register the class device\n"); | ||
252 | goto out_irq; | ||
253 | } | ||
254 | |||
255 | if (client->irq >= 0) { | ||
256 | ret = request_irq(client->irq, ds3232_irq, 0, | ||
257 | "ds3232", client); | ||
258 | if (ret) { | ||
259 | dev_err(&client->dev, "unable to request IRQ\n"); | ||
260 | goto out_free; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | return 0; | ||
265 | |||
266 | out_irq: | ||
267 | if (client->irq >= 0) | ||
268 | free_irq(client->irq, client); | ||
269 | |||
270 | out_free: | ||
271 | i2c_set_clientdata(client, NULL); | ||
272 | kfree(ds3232); | ||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | static int __devexit ds3232_remove(struct i2c_client *client) | ||
277 | { | ||
278 | struct ds3232 *ds3232 = i2c_get_clientdata(client); | ||
279 | |||
280 | if (client->irq >= 0) { | ||
281 | mutex_lock(&ds3232->mutex); | ||
282 | ds3232->exiting = 1; | ||
283 | mutex_unlock(&ds3232->mutex); | ||
284 | |||
285 | free_irq(client->irq, client); | ||
286 | flush_scheduled_work(); | ||
287 | } | ||
288 | |||
289 | rtc_device_unregister(ds3232->rtc); | ||
290 | i2c_set_clientdata(client, NULL); | ||
291 | kfree(ds3232); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static const struct i2c_device_id ds3232_id[] = { | ||
296 | { "ds3232", 0 }, | ||
297 | { } | ||
298 | }; | ||
299 | MODULE_DEVICE_TABLE(i2c, ds3232_id); | ||
300 | |||
301 | static struct i2c_driver ds3232_driver = { | ||
302 | .driver = { | ||
303 | .name = "rtc-ds3232", | ||
304 | .owner = THIS_MODULE, | ||
305 | }, | ||
306 | .probe = ds3232_probe, | ||
307 | .remove = __devexit_p(ds3232_remove), | ||
308 | .id_table = ds3232_id, | ||
309 | }; | ||
310 | |||
311 | static int __init ds3232_init(void) | ||
312 | { | ||
313 | return i2c_add_driver(&ds3232_driver); | ||
314 | } | ||
315 | |||
316 | static void __exit ds3232_exit(void) | ||
317 | { | ||
318 | i2c_del_driver(&ds3232_driver); | ||
319 | } | ||
320 | |||
321 | module_init(ds3232_init); | ||
322 | module_exit(ds3232_exit); | ||
323 | |||
324 | MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>"); | ||
325 | MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver"); | ||
326 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c index e4de8f37ae4a..4cf2e70c5078 100644 --- a/drivers/rtc/rtc-fm3130.c +++ b/drivers/rtc/rtc-fm3130.c | |||
@@ -52,8 +52,8 @@ struct fm3130 { | |||
52 | struct i2c_msg msg[4]; | 52 | struct i2c_msg msg[4]; |
53 | struct i2c_client *client; | 53 | struct i2c_client *client; |
54 | struct rtc_device *rtc; | 54 | struct rtc_device *rtc; |
55 | int alarm_valid; | ||
55 | int data_valid; | 56 | int data_valid; |
56 | int alarm; | ||
57 | }; | 57 | }; |
58 | static const struct i2c_device_id fm3130_id[] = { | 58 | static const struct i2c_device_id fm3130_id[] = { |
59 | { "fm3130", 0 }, | 59 | { "fm3130", 0 }, |
@@ -87,11 +87,7 @@ static void fm3130_rtc_mode(struct device *dev, int mode) | |||
87 | dev_dbg(dev, "invalid mode %d\n", mode); | 87 | dev_dbg(dev, "invalid mode %d\n", mode); |
88 | break; | 88 | break; |
89 | } | 89 | } |
90 | /* Checking for alarm */ | 90 | |
91 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { | ||
92 | fm3130->alarm = 1; | ||
93 | fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; | ||
94 | } | ||
95 | i2c_smbus_write_byte_data(fm3130->client, | 91 | i2c_smbus_write_byte_data(fm3130->client, |
96 | FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]); | 92 | FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]); |
97 | } | 93 | } |
@@ -208,6 +204,17 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
208 | struct fm3130 *fm3130 = dev_get_drvdata(dev); | 204 | struct fm3130 *fm3130 = dev_get_drvdata(dev); |
209 | int tmp; | 205 | int tmp; |
210 | struct rtc_time *tm = &alrm->time; | 206 | struct rtc_time *tm = &alrm->time; |
207 | |||
208 | if (!fm3130->alarm_valid) { | ||
209 | /* | ||
210 | * We have invalid alarm in RTC, probably due to battery faults | ||
211 | * or other problems. Return EIO for now, it will allow us to | ||
212 | * set alarm value later instead of error during probing which | ||
213 | * disables device | ||
214 | */ | ||
215 | return -EIO; | ||
216 | } | ||
217 | |||
211 | /* read the RTC alarm registers all at once */ | 218 | /* read the RTC alarm registers all at once */ |
212 | tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), | 219 | tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), |
213 | &fm3130->msg[2], 2); | 220 | &fm3130->msg[2], 2); |
@@ -222,20 +229,31 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
222 | fm3130->regs[FM3130_ALARM_DATE], | 229 | fm3130->regs[FM3130_ALARM_DATE], |
223 | fm3130->regs[FM3130_ALARM_MONTHS]); | 230 | fm3130->regs[FM3130_ALARM_MONTHS]); |
224 | 231 | ||
225 | |||
226 | tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F); | 232 | tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F); |
227 | tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F); | 233 | tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F); |
228 | tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F); | 234 | tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F); |
229 | tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F); | 235 | tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F); |
230 | tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F); | 236 | tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F); |
237 | |||
231 | if (tm->tm_mon > 0) | 238 | if (tm->tm_mon > 0) |
232 | tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ | 239 | tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ |
240 | |||
233 | dev_dbg(dev, "%s secs=%d, mins=%d, " | 241 | dev_dbg(dev, "%s secs=%d, mins=%d, " |
234 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", | 242 | "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", |
235 | "read alarm", tm->tm_sec, tm->tm_min, | 243 | "read alarm", tm->tm_sec, tm->tm_min, |
236 | tm->tm_hour, tm->tm_mday, | 244 | tm->tm_hour, tm->tm_mday, |
237 | tm->tm_mon, tm->tm_year, tm->tm_wday); | 245 | tm->tm_mon, tm->tm_year, tm->tm_wday); |
238 | 246 | ||
247 | /* check if alarm enabled */ | ||
248 | fm3130->regs[FM3130_RTC_CONTROL] = | ||
249 | i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); | ||
250 | |||
251 | if ((fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AEN) && | ||
252 | (~fm3130->regs[FM3130_RTC_CONTROL] & | ||
253 | FM3130_RTC_CONTROL_BIT_CAL)) { | ||
254 | alrm->enabled = 1; | ||
255 | } | ||
256 | |||
239 | return 0; | 257 | return 0; |
240 | } | 258 | } |
241 | 259 | ||
@@ -251,25 +269,20 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
251 | tm->tm_hour, tm->tm_mday, | 269 | tm->tm_hour, tm->tm_mday, |
252 | tm->tm_mon, tm->tm_year, tm->tm_wday); | 270 | tm->tm_mon, tm->tm_year, tm->tm_wday); |
253 | 271 | ||
254 | if (tm->tm_sec != -1) | 272 | fm3130->regs[FM3130_ALARM_SECONDS] = |
255 | fm3130->regs[FM3130_ALARM_SECONDS] = | 273 | (tm->tm_sec != -1) ? bin2bcd(tm->tm_sec) : 0x80; |
256 | bin2bcd(tm->tm_sec) | 0x80; | ||
257 | 274 | ||
258 | if (tm->tm_min != -1) | 275 | fm3130->regs[FM3130_ALARM_MINUTES] = |
259 | fm3130->regs[FM3130_ALARM_MINUTES] = | 276 | (tm->tm_min != -1) ? bin2bcd(tm->tm_min) : 0x80; |
260 | bin2bcd(tm->tm_min) | 0x80; | ||
261 | 277 | ||
262 | if (tm->tm_hour != -1) | 278 | fm3130->regs[FM3130_ALARM_HOURS] = |
263 | fm3130->regs[FM3130_ALARM_HOURS] = | 279 | (tm->tm_hour != -1) ? bin2bcd(tm->tm_hour) : 0x80; |
264 | bin2bcd(tm->tm_hour) | 0x80; | ||
265 | 280 | ||
266 | if (tm->tm_mday != -1) | 281 | fm3130->regs[FM3130_ALARM_DATE] = |
267 | fm3130->regs[FM3130_ALARM_DATE] = | 282 | (tm->tm_mday != -1) ? bin2bcd(tm->tm_mday) : 0x80; |
268 | bin2bcd(tm->tm_mday) | 0x80; | ||
269 | 283 | ||
270 | if (tm->tm_mon != -1) | 284 | fm3130->regs[FM3130_ALARM_MONTHS] = |
271 | fm3130->regs[FM3130_ALARM_MONTHS] = | 285 | (tm->tm_mon != -1) ? bin2bcd(tm->tm_mon + 1) : 0x80; |
272 | bin2bcd(tm->tm_mon + 1) | 0x80; | ||
273 | 286 | ||
274 | dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n", | 287 | dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n", |
275 | fm3130->regs[FM3130_ALARM_SECONDS], | 288 | fm3130->regs[FM3130_ALARM_SECONDS], |
@@ -285,11 +298,8 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
285 | } | 298 | } |
286 | fm3130->regs[FM3130_RTC_CONTROL] = | 299 | fm3130->regs[FM3130_RTC_CONTROL] = |
287 | i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); | 300 | i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); |
288 | /* Checking for alarm */ | 301 | |
289 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { | 302 | /* enable or disable alarm */ |
290 | fm3130->alarm = 1; | ||
291 | fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; | ||
292 | } | ||
293 | if (alrm->enabled) { | 303 | if (alrm->enabled) { |
294 | i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, | 304 | i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, |
295 | (fm3130->regs[FM3130_RTC_CONTROL] & | 305 | (fm3130->regs[FM3130_RTC_CONTROL] & |
@@ -298,16 +308,55 @@ static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
298 | } else { | 308 | } else { |
299 | i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, | 309 | i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, |
300 | fm3130->regs[FM3130_RTC_CONTROL] & | 310 | fm3130->regs[FM3130_RTC_CONTROL] & |
301 | ~(FM3130_RTC_CONTROL_BIT_AEN)); | 311 | ~(FM3130_RTC_CONTROL_BIT_CAL) & |
312 | ~(FM3130_RTC_CONTROL_BIT_AEN)); | ||
302 | } | 313 | } |
314 | |||
315 | /* We assume here that data is valid once written */ | ||
316 | if (!fm3130->alarm_valid) | ||
317 | fm3130->alarm_valid = 1; | ||
318 | |||
303 | return 0; | 319 | return 0; |
304 | } | 320 | } |
305 | 321 | ||
322 | static int fm3130_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
323 | { | ||
324 | struct fm3130 *fm3130 = dev_get_drvdata(dev); | ||
325 | int ret = 0; | ||
326 | |||
327 | fm3130->regs[FM3130_RTC_CONTROL] = | ||
328 | i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); | ||
329 | |||
330 | dev_dbg(dev, "alarm_irq_enable: enable=%d, FM3130_RTC_CONTROL=%02x\n", | ||
331 | enabled, fm3130->regs[FM3130_RTC_CONTROL]); | ||
332 | |||
333 | switch (enabled) { | ||
334 | case 0: /* alarm off */ | ||
335 | ret = i2c_smbus_write_byte_data(fm3130->client, | ||
336 | FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL] & | ||
337 | ~(FM3130_RTC_CONTROL_BIT_CAL) & | ||
338 | ~(FM3130_RTC_CONTROL_BIT_AEN)); | ||
339 | break; | ||
340 | case 1: /* alarm on */ | ||
341 | ret = i2c_smbus_write_byte_data(fm3130->client, | ||
342 | FM3130_RTC_CONTROL, (fm3130->regs[FM3130_RTC_CONTROL] & | ||
343 | ~(FM3130_RTC_CONTROL_BIT_CAL)) | | ||
344 | FM3130_RTC_CONTROL_BIT_AEN); | ||
345 | break; | ||
346 | default: | ||
347 | ret = -EINVAL; | ||
348 | break; | ||
349 | } | ||
350 | |||
351 | return ret; | ||
352 | } | ||
353 | |||
306 | static const struct rtc_class_ops fm3130_rtc_ops = { | 354 | static const struct rtc_class_ops fm3130_rtc_ops = { |
307 | .read_time = fm3130_get_time, | 355 | .read_time = fm3130_get_time, |
308 | .set_time = fm3130_set_time, | 356 | .set_time = fm3130_set_time, |
309 | .read_alarm = fm3130_read_alarm, | 357 | .read_alarm = fm3130_read_alarm, |
310 | .set_alarm = fm3130_set_alarm, | 358 | .set_alarm = fm3130_set_alarm, |
359 | .alarm_irq_enable = fm3130_alarm_irq_enable, | ||
311 | }; | 360 | }; |
312 | 361 | ||
313 | static struct i2c_driver fm3130_driver; | 362 | static struct i2c_driver fm3130_driver; |
@@ -356,6 +405,7 @@ static int __devinit fm3130_probe(struct i2c_client *client, | |||
356 | fm3130->msg[3].len = FM3130_ALARM_REGS; | 405 | fm3130->msg[3].len = FM3130_ALARM_REGS; |
357 | fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS]; | 406 | fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS]; |
358 | 407 | ||
408 | fm3130->alarm_valid = 0; | ||
359 | fm3130->data_valid = 0; | 409 | fm3130->data_valid = 0; |
360 | 410 | ||
361 | tmp = i2c_transfer(adapter, fm3130->msg, 4); | 411 | tmp = i2c_transfer(adapter, fm3130->msg, 4); |
@@ -370,12 +420,6 @@ static int __devinit fm3130_probe(struct i2c_client *client, | |||
370 | fm3130->regs[FM3130_CAL_CONTROL] = | 420 | fm3130->regs[FM3130_CAL_CONTROL] = |
371 | i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL); | 421 | i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL); |
372 | 422 | ||
373 | /* Checking for alarm */ | ||
374 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { | ||
375 | fm3130->alarm = 1; | ||
376 | fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; | ||
377 | } | ||
378 | |||
379 | /* Disabling calibration mode */ | 423 | /* Disabling calibration mode */ |
380 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) { | 424 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) { |
381 | i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, | 425 | i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, |
@@ -400,44 +444,79 @@ static int __devinit fm3130_probe(struct i2c_client *client, | |||
400 | fm3130->regs[FM3130_CAL_CONTROL] & | 444 | fm3130->regs[FM3130_CAL_CONTROL] & |
401 | ~(FM3130_CAL_CONTROL_BIT_nOSCEN)); | 445 | ~(FM3130_CAL_CONTROL_BIT_nOSCEN)); |
402 | 446 | ||
403 | /* oscillator fault? clear flag, and warn */ | 447 | /* low battery? clear flag, and warn */ |
404 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) | 448 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) { |
449 | i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, | ||
450 | fm3130->regs[FM3130_RTC_CONTROL] & | ||
451 | ~(FM3130_RTC_CONTROL_BIT_LB)); | ||
405 | dev_warn(&client->dev, "Low battery!\n"); | 452 | dev_warn(&client->dev, "Low battery!\n"); |
453 | } | ||
406 | 454 | ||
407 | /* oscillator fault? clear flag, and warn */ | 455 | /* check if Power On Reset bit is set */ |
408 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) { | 456 | if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) { |
409 | i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, | 457 | i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, |
410 | fm3130->regs[FM3130_RTC_CONTROL] & | 458 | fm3130->regs[FM3130_RTC_CONTROL] & |
411 | ~FM3130_RTC_CONTROL_BIT_POR); | 459 | ~FM3130_RTC_CONTROL_BIT_POR); |
412 | dev_warn(&client->dev, "SET TIME!\n"); | 460 | dev_dbg(&client->dev, "POR bit is set\n"); |
413 | } | 461 | } |
414 | /* ACS is controlled by alarm */ | 462 | /* ACS is controlled by alarm */ |
415 | i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80); | 463 | i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80); |
416 | 464 | ||
417 | /* TODO */ | 465 | /* alarm registers sanity check */ |
418 | /* TODO need to sanity check alarm */ | 466 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); |
419 | tmp = fm3130->regs[FM3130_RTC_SECONDS]; | 467 | if (tmp > 59) |
420 | tmp = bcd2bin(tmp & 0x7f); | 468 | goto bad_alarm; |
421 | if (tmp > 60) | 469 | |
422 | goto exit_bad; | ||
423 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); | 470 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); |
424 | if (tmp > 60) | 471 | if (tmp > 59) |
425 | goto exit_bad; | 472 | goto bad_alarm; |
473 | |||
474 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f); | ||
475 | if (tmp > 23) | ||
476 | goto bad_alarm; | ||
426 | 477 | ||
427 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); | 478 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); |
428 | if (tmp == 0 || tmp > 31) | 479 | if (tmp == 0 || tmp > 31) |
429 | goto exit_bad; | 480 | goto bad_alarm; |
430 | 481 | ||
431 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); | 482 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); |
432 | if (tmp == 0 || tmp > 12) | 483 | if (tmp == 0 || tmp > 12) |
433 | goto exit_bad; | 484 | goto bad_alarm; |
434 | 485 | ||
435 | tmp = fm3130->regs[FM3130_RTC_HOURS]; | 486 | fm3130->alarm_valid = 1; |
487 | |||
488 | bad_alarm: | ||
489 | |||
490 | /* clock registers sanity chek */ | ||
491 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); | ||
492 | if (tmp > 59) | ||
493 | goto bad_clock; | ||
494 | |||
495 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); | ||
496 | if (tmp > 59) | ||
497 | goto bad_clock; | ||
498 | |||
499 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f); | ||
500 | if (tmp > 23) | ||
501 | goto bad_clock; | ||
502 | |||
503 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_DAY] & 0x7); | ||
504 | if (tmp == 0 || tmp > 7) | ||
505 | goto bad_clock; | ||
506 | |||
507 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); | ||
508 | if (tmp == 0 || tmp > 31) | ||
509 | goto bad_clock; | ||
510 | |||
511 | tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); | ||
512 | if (tmp == 0 || tmp > 12) | ||
513 | goto bad_clock; | ||
436 | 514 | ||
437 | fm3130->data_valid = 1; | 515 | fm3130->data_valid = 1; |
438 | 516 | ||
439 | exit_bad: | 517 | bad_clock: |
440 | if (!fm3130->data_valid) | 518 | |
519 | if (!fm3130->data_valid || !fm3130->alarm_valid) | ||
441 | dev_dbg(&client->dev, | 520 | dev_dbg(&client->dev, |
442 | "%s: %02x %02x %02x %02x %02x %02x %02x %02x" | 521 | "%s: %02x %02x %02x %02x %02x %02x %02x %02x" |
443 | "%02x %02x %02x %02x %02x %02x %02x\n", | 522 | "%02x %02x %02x %02x %02x %02x %02x\n", |
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c new file mode 100644 index 000000000000..2dd3c0163272 --- /dev/null +++ b/drivers/rtc/rtc-imxdi.c | |||
@@ -0,0 +1,519 @@ | |||
1 | /* | ||
2 | * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. | ||
3 | * Copyright 2010 Orex Computed Radiography | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | * The code contained herein is licensed under the GNU General Public | ||
8 | * License. You may obtain a copy of the GNU General Public License | ||
9 | * Version 2 or later at the following locations: | ||
10 | * | ||
11 | * http://www.opensource.org/licenses/gpl-license.html | ||
12 | * http://www.gnu.org/copyleft/gpl.html | ||
13 | */ | ||
14 | |||
15 | /* based on rtc-mc13892.c */ | ||
16 | |||
17 | /* | ||
18 | * This driver uses the 47-bit 32 kHz counter in the Freescale DryIce block | ||
19 | * to implement a Linux RTC. Times and alarms are truncated to seconds. | ||
20 | * Since the RTC framework performs API locking via rtc->ops_lock the | ||
21 | * only simultaneous accesses we need to deal with is updating DryIce | ||
22 | * registers while servicing an alarm. | ||
23 | * | ||
24 | * Note that reading the DSR (DryIce Status Register) automatically clears | ||
25 | * the WCF (Write Complete Flag). All DryIce writes are synchronized to the | ||
26 | * LP (Low Power) domain and set the WCF upon completion. Writes to the | ||
27 | * DIER (DryIce Interrupt Enable Register) are the only exception. These | ||
28 | * occur at normal bus speeds and do not set WCF. Periodic interrupts are | ||
29 | * not supported by the hardware. | ||
30 | */ | ||
31 | |||
32 | #include <linux/io.h> | ||
33 | #include <linux/clk.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/platform_device.h> | ||
37 | #include <linux/rtc.h> | ||
38 | #include <linux/workqueue.h> | ||
39 | |||
40 | /* DryIce Register Definitions */ | ||
41 | |||
42 | #define DTCMR 0x00 /* Time Counter MSB Reg */ | ||
43 | #define DTCLR 0x04 /* Time Counter LSB Reg */ | ||
44 | |||
45 | #define DCAMR 0x08 /* Clock Alarm MSB Reg */ | ||
46 | #define DCALR 0x0c /* Clock Alarm LSB Reg */ | ||
47 | #define DCAMR_UNSET 0xFFFFFFFF /* doomsday - 1 sec */ | ||
48 | |||
49 | #define DCR 0x10 /* Control Reg */ | ||
50 | #define DCR_TCE (1 << 3) /* Time Counter Enable */ | ||
51 | |||
52 | #define DSR 0x14 /* Status Reg */ | ||
53 | #define DSR_WBF (1 << 10) /* Write Busy Flag */ | ||
54 | #define DSR_WNF (1 << 9) /* Write Next Flag */ | ||
55 | #define DSR_WCF (1 << 8) /* Write Complete Flag */ | ||
56 | #define DSR_WEF (1 << 7) /* Write Error Flag */ | ||
57 | #define DSR_CAF (1 << 4) /* Clock Alarm Flag */ | ||
58 | #define DSR_NVF (1 << 1) /* Non-Valid Flag */ | ||
59 | #define DSR_SVF (1 << 0) /* Security Violation Flag */ | ||
60 | |||
61 | #define DIER 0x18 /* Interrupt Enable Reg */ | ||
62 | #define DIER_WNIE (1 << 9) /* Write Next Interrupt Enable */ | ||
63 | #define DIER_WCIE (1 << 8) /* Write Complete Interrupt Enable */ | ||
64 | #define DIER_WEIE (1 << 7) /* Write Error Interrupt Enable */ | ||
65 | #define DIER_CAIE (1 << 4) /* Clock Alarm Interrupt Enable */ | ||
66 | |||
67 | /** | ||
68 | * struct imxdi_dev - private imxdi rtc data | ||
69 | * @pdev: pionter to platform dev | ||
70 | * @rtc: pointer to rtc struct | ||
71 | * @ioaddr: IO registers pointer | ||
72 | * @irq: dryice normal interrupt | ||
73 | * @clk: input reference clock | ||
74 | * @dsr: copy of the DSR register | ||
75 | * @irq_lock: interrupt enable register (DIER) lock | ||
76 | * @write_wait: registers write complete queue | ||
77 | * @write_mutex: serialize registers write | ||
78 | * @work: schedule alarm work | ||
79 | */ | ||
80 | struct imxdi_dev { | ||
81 | struct platform_device *pdev; | ||
82 | struct rtc_device *rtc; | ||
83 | void __iomem *ioaddr; | ||
84 | int irq; | ||
85 | struct clk *clk; | ||
86 | u32 dsr; | ||
87 | spinlock_t irq_lock; | ||
88 | wait_queue_head_t write_wait; | ||
89 | struct mutex write_mutex; | ||
90 | struct work_struct work; | ||
91 | }; | ||
92 | |||
93 | /* | ||
94 | * enable a dryice interrupt | ||
95 | */ | ||
96 | static void di_int_enable(struct imxdi_dev *imxdi, u32 intr) | ||
97 | { | ||
98 | unsigned long flags; | ||
99 | |||
100 | spin_lock_irqsave(&imxdi->irq_lock, flags); | ||
101 | __raw_writel(__raw_readl(imxdi->ioaddr + DIER) | intr, | ||
102 | imxdi->ioaddr + DIER); | ||
103 | spin_unlock_irqrestore(&imxdi->irq_lock, flags); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * disable a dryice interrupt | ||
108 | */ | ||
109 | static void di_int_disable(struct imxdi_dev *imxdi, u32 intr) | ||
110 | { | ||
111 | unsigned long flags; | ||
112 | |||
113 | spin_lock_irqsave(&imxdi->irq_lock, flags); | ||
114 | __raw_writel(__raw_readl(imxdi->ioaddr + DIER) & ~intr, | ||
115 | imxdi->ioaddr + DIER); | ||
116 | spin_unlock_irqrestore(&imxdi->irq_lock, flags); | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * This function attempts to clear the dryice write-error flag. | ||
121 | * | ||
122 | * A dryice write error is similar to a bus fault and should not occur in | ||
123 | * normal operation. Clearing the flag requires another write, so the root | ||
124 | * cause of the problem may need to be fixed before the flag can be cleared. | ||
125 | */ | ||
126 | static void clear_write_error(struct imxdi_dev *imxdi) | ||
127 | { | ||
128 | int cnt; | ||
129 | |||
130 | dev_warn(&imxdi->pdev->dev, "WARNING: Register write error!\n"); | ||
131 | |||
132 | /* clear the write error flag */ | ||
133 | __raw_writel(DSR_WEF, imxdi->ioaddr + DSR); | ||
134 | |||
135 | /* wait for it to take effect */ | ||
136 | for (cnt = 0; cnt < 1000; cnt++) { | ||
137 | if ((__raw_readl(imxdi->ioaddr + DSR) & DSR_WEF) == 0) | ||
138 | return; | ||
139 | udelay(10); | ||
140 | } | ||
141 | dev_err(&imxdi->pdev->dev, | ||
142 | "ERROR: Cannot clear write-error flag!\n"); | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Write a dryice register and wait until it completes. | ||
147 | * | ||
148 | * This function uses interrupts to determine when the | ||
149 | * write has completed. | ||
150 | */ | ||
151 | static int di_write_wait(struct imxdi_dev *imxdi, u32 val, int reg) | ||
152 | { | ||
153 | int ret; | ||
154 | int rc = 0; | ||
155 | |||
156 | /* serialize register writes */ | ||
157 | mutex_lock(&imxdi->write_mutex); | ||
158 | |||
159 | /* enable the write-complete interrupt */ | ||
160 | di_int_enable(imxdi, DIER_WCIE); | ||
161 | |||
162 | imxdi->dsr = 0; | ||
163 | |||
164 | /* do the register write */ | ||
165 | __raw_writel(val, imxdi->ioaddr + reg); | ||
166 | |||
167 | /* wait for the write to finish */ | ||
168 | ret = wait_event_interruptible_timeout(imxdi->write_wait, | ||
169 | imxdi->dsr & (DSR_WCF | DSR_WEF), msecs_to_jiffies(1)); | ||
170 | if (ret < 0) { | ||
171 | rc = ret; | ||
172 | goto out; | ||
173 | } else if (ret == 0) { | ||
174 | dev_warn(&imxdi->pdev->dev, | ||
175 | "Write-wait timeout " | ||
176 | "val = 0x%08x reg = 0x%08x\n", val, reg); | ||
177 | } | ||
178 | |||
179 | /* check for write error */ | ||
180 | if (imxdi->dsr & DSR_WEF) { | ||
181 | clear_write_error(imxdi); | ||
182 | rc = -EIO; | ||
183 | } | ||
184 | |||
185 | out: | ||
186 | mutex_unlock(&imxdi->write_mutex); | ||
187 | |||
188 | return rc; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * read the seconds portion of the current time from the dryice time counter | ||
193 | */ | ||
194 | static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
195 | { | ||
196 | struct imxdi_dev *imxdi = dev_get_drvdata(dev); | ||
197 | unsigned long now; | ||
198 | |||
199 | now = __raw_readl(imxdi->ioaddr + DTCMR); | ||
200 | rtc_time_to_tm(now, tm); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * set the seconds portion of dryice time counter and clear the | ||
207 | * fractional part. | ||
208 | */ | ||
209 | static int dryice_rtc_set_mmss(struct device *dev, unsigned long secs) | ||
210 | { | ||
211 | struct imxdi_dev *imxdi = dev_get_drvdata(dev); | ||
212 | int rc; | ||
213 | |||
214 | /* zero the fractional part first */ | ||
215 | rc = di_write_wait(imxdi, 0, DTCLR); | ||
216 | if (rc == 0) | ||
217 | rc = di_write_wait(imxdi, secs, DTCMR); | ||
218 | |||
219 | return rc; | ||
220 | } | ||
221 | |||
222 | static int dryice_rtc_alarm_irq_enable(struct device *dev, | ||
223 | unsigned int enabled) | ||
224 | { | ||
225 | struct imxdi_dev *imxdi = dev_get_drvdata(dev); | ||
226 | |||
227 | if (enabled) | ||
228 | di_int_enable(imxdi, DIER_CAIE); | ||
229 | else | ||
230 | di_int_disable(imxdi, DIER_CAIE); | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * read the seconds portion of the alarm register. | ||
237 | * the fractional part of the alarm register is always zero. | ||
238 | */ | ||
239 | static int dryice_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
240 | { | ||
241 | struct imxdi_dev *imxdi = dev_get_drvdata(dev); | ||
242 | u32 dcamr; | ||
243 | |||
244 | dcamr = __raw_readl(imxdi->ioaddr + DCAMR); | ||
245 | rtc_time_to_tm(dcamr, &alarm->time); | ||
246 | |||
247 | /* alarm is enabled if the interrupt is enabled */ | ||
248 | alarm->enabled = (__raw_readl(imxdi->ioaddr + DIER) & DIER_CAIE) != 0; | ||
249 | |||
250 | /* don't allow the DSR read to mess up DSR_WCF */ | ||
251 | mutex_lock(&imxdi->write_mutex); | ||
252 | |||
253 | /* alarm is pending if the alarm flag is set */ | ||
254 | alarm->pending = (__raw_readl(imxdi->ioaddr + DSR) & DSR_CAF) != 0; | ||
255 | |||
256 | mutex_unlock(&imxdi->write_mutex); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * set the seconds portion of dryice alarm register | ||
263 | */ | ||
264 | static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
265 | { | ||
266 | struct imxdi_dev *imxdi = dev_get_drvdata(dev); | ||
267 | unsigned long now; | ||
268 | unsigned long alarm_time; | ||
269 | int rc; | ||
270 | |||
271 | rc = rtc_tm_to_time(&alarm->time, &alarm_time); | ||
272 | if (rc) | ||
273 | return rc; | ||
274 | |||
275 | /* don't allow setting alarm in the past */ | ||
276 | now = __raw_readl(imxdi->ioaddr + DTCMR); | ||
277 | if (alarm_time < now) | ||
278 | return -EINVAL; | ||
279 | |||
280 | /* write the new alarm time */ | ||
281 | rc = di_write_wait(imxdi, (u32)alarm_time, DCAMR); | ||
282 | if (rc) | ||
283 | return rc; | ||
284 | |||
285 | if (alarm->enabled) | ||
286 | di_int_enable(imxdi, DIER_CAIE); /* enable alarm intr */ | ||
287 | else | ||
288 | di_int_disable(imxdi, DIER_CAIE); /* disable alarm intr */ | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static struct rtc_class_ops dryice_rtc_ops = { | ||
294 | .read_time = dryice_rtc_read_time, | ||
295 | .set_mmss = dryice_rtc_set_mmss, | ||
296 | .alarm_irq_enable = dryice_rtc_alarm_irq_enable, | ||
297 | .read_alarm = dryice_rtc_read_alarm, | ||
298 | .set_alarm = dryice_rtc_set_alarm, | ||
299 | }; | ||
300 | |||
301 | /* | ||
302 | * dryice "normal" interrupt handler | ||
303 | */ | ||
304 | static irqreturn_t dryice_norm_irq(int irq, void *dev_id) | ||
305 | { | ||
306 | struct imxdi_dev *imxdi = dev_id; | ||
307 | u32 dsr, dier; | ||
308 | irqreturn_t rc = IRQ_NONE; | ||
309 | |||
310 | dier = __raw_readl(imxdi->ioaddr + DIER); | ||
311 | |||
312 | /* handle write complete and write error cases */ | ||
313 | if ((dier & DIER_WCIE)) { | ||
314 | /*If the write wait queue is empty then there is no pending | ||
315 | operations. It means the interrupt is for DryIce -Security. | ||
316 | IRQ must be returned as none.*/ | ||
317 | if (list_empty_careful(&imxdi->write_wait.task_list)) | ||
318 | return rc; | ||
319 | |||
320 | /* DSR_WCF clears itself on DSR read */ | ||
321 | dsr = __raw_readl(imxdi->ioaddr + DSR); | ||
322 | if ((dsr & (DSR_WCF | DSR_WEF))) { | ||
323 | /* mask the interrupt */ | ||
324 | di_int_disable(imxdi, DIER_WCIE); | ||
325 | |||
326 | /* save the dsr value for the wait queue */ | ||
327 | imxdi->dsr |= dsr; | ||
328 | |||
329 | wake_up_interruptible(&imxdi->write_wait); | ||
330 | rc = IRQ_HANDLED; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | /* handle the alarm case */ | ||
335 | if ((dier & DIER_CAIE)) { | ||
336 | /* DSR_WCF clears itself on DSR read */ | ||
337 | dsr = __raw_readl(imxdi->ioaddr + DSR); | ||
338 | if (dsr & DSR_CAF) { | ||
339 | /* mask the interrupt */ | ||
340 | di_int_disable(imxdi, DIER_CAIE); | ||
341 | |||
342 | /* finish alarm in user context */ | ||
343 | schedule_work(&imxdi->work); | ||
344 | rc = IRQ_HANDLED; | ||
345 | } | ||
346 | } | ||
347 | return rc; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * post the alarm event from user context so it can sleep | ||
352 | * on the write completion. | ||
353 | */ | ||
354 | static void dryice_work(struct work_struct *work) | ||
355 | { | ||
356 | struct imxdi_dev *imxdi = container_of(work, | ||
357 | struct imxdi_dev, work); | ||
358 | |||
359 | /* dismiss the interrupt (ignore error) */ | ||
360 | di_write_wait(imxdi, DSR_CAF, DSR); | ||
361 | |||
362 | /* pass the alarm event to the rtc framework. */ | ||
363 | rtc_update_irq(imxdi->rtc, 1, RTC_AF | RTC_IRQF); | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * probe for dryice rtc device | ||
368 | */ | ||
369 | static int dryice_rtc_probe(struct platform_device *pdev) | ||
370 | { | ||
371 | struct resource *res; | ||
372 | struct imxdi_dev *imxdi; | ||
373 | int rc; | ||
374 | |||
375 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
376 | if (!res) | ||
377 | return -ENODEV; | ||
378 | |||
379 | imxdi = devm_kzalloc(&pdev->dev, sizeof(*imxdi), GFP_KERNEL); | ||
380 | if (!imxdi) | ||
381 | return -ENOMEM; | ||
382 | |||
383 | imxdi->pdev = pdev; | ||
384 | |||
385 | if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), | ||
386 | pdev->name)) | ||
387 | return -EBUSY; | ||
388 | |||
389 | imxdi->ioaddr = devm_ioremap(&pdev->dev, res->start, | ||
390 | resource_size(res)); | ||
391 | if (imxdi->ioaddr == NULL) | ||
392 | return -ENOMEM; | ||
393 | |||
394 | imxdi->irq = platform_get_irq(pdev, 0); | ||
395 | if (imxdi->irq < 0) | ||
396 | return imxdi->irq; | ||
397 | |||
398 | init_waitqueue_head(&imxdi->write_wait); | ||
399 | |||
400 | INIT_WORK(&imxdi->work, dryice_work); | ||
401 | |||
402 | mutex_init(&imxdi->write_mutex); | ||
403 | |||
404 | imxdi->clk = clk_get(&pdev->dev, NULL); | ||
405 | if (IS_ERR(imxdi->clk)) | ||
406 | return PTR_ERR(imxdi->clk); | ||
407 | clk_enable(imxdi->clk); | ||
408 | |||
409 | /* | ||
410 | * Initialize dryice hardware | ||
411 | */ | ||
412 | |||
413 | /* mask all interrupts */ | ||
414 | __raw_writel(0, imxdi->ioaddr + DIER); | ||
415 | |||
416 | rc = devm_request_irq(&pdev->dev, imxdi->irq, dryice_norm_irq, | ||
417 | IRQF_SHARED, pdev->name, imxdi); | ||
418 | if (rc) { | ||
419 | dev_warn(&pdev->dev, "interrupt not available.\n"); | ||
420 | goto err; | ||
421 | } | ||
422 | |||
423 | /* put dryice into valid state */ | ||
424 | if (__raw_readl(imxdi->ioaddr + DSR) & DSR_NVF) { | ||
425 | rc = di_write_wait(imxdi, DSR_NVF | DSR_SVF, DSR); | ||
426 | if (rc) | ||
427 | goto err; | ||
428 | } | ||
429 | |||
430 | /* initialize alarm */ | ||
431 | rc = di_write_wait(imxdi, DCAMR_UNSET, DCAMR); | ||
432 | if (rc) | ||
433 | goto err; | ||
434 | rc = di_write_wait(imxdi, 0, DCALR); | ||
435 | if (rc) | ||
436 | goto err; | ||
437 | |||
438 | /* clear alarm flag */ | ||
439 | if (__raw_readl(imxdi->ioaddr + DSR) & DSR_CAF) { | ||
440 | rc = di_write_wait(imxdi, DSR_CAF, DSR); | ||
441 | if (rc) | ||
442 | goto err; | ||
443 | } | ||
444 | |||
445 | /* the timer won't count if it has never been written to */ | ||
446 | if (__raw_readl(imxdi->ioaddr + DTCMR) == 0) { | ||
447 | rc = di_write_wait(imxdi, 0, DTCMR); | ||
448 | if (rc) | ||
449 | goto err; | ||
450 | } | ||
451 | |||
452 | /* start keeping time */ | ||
453 | if (!(__raw_readl(imxdi->ioaddr + DCR) & DCR_TCE)) { | ||
454 | rc = di_write_wait(imxdi, | ||
455 | __raw_readl(imxdi->ioaddr + DCR) | DCR_TCE, | ||
456 | DCR); | ||
457 | if (rc) | ||
458 | goto err; | ||
459 | } | ||
460 | |||
461 | platform_set_drvdata(pdev, imxdi); | ||
462 | imxdi->rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
463 | &dryice_rtc_ops, THIS_MODULE); | ||
464 | if (IS_ERR(imxdi->rtc)) { | ||
465 | rc = PTR_ERR(imxdi->rtc); | ||
466 | goto err; | ||
467 | } | ||
468 | |||
469 | return 0; | ||
470 | |||
471 | err: | ||
472 | clk_disable(imxdi->clk); | ||
473 | clk_put(imxdi->clk); | ||
474 | |||
475 | return rc; | ||
476 | } | ||
477 | |||
478 | static int __devexit dryice_rtc_remove(struct platform_device *pdev) | ||
479 | { | ||
480 | struct imxdi_dev *imxdi = platform_get_drvdata(pdev); | ||
481 | |||
482 | flush_work(&imxdi->work); | ||
483 | |||
484 | /* mask all interrupts */ | ||
485 | __raw_writel(0, imxdi->ioaddr + DIER); | ||
486 | |||
487 | rtc_device_unregister(imxdi->rtc); | ||
488 | |||
489 | clk_disable(imxdi->clk); | ||
490 | clk_put(imxdi->clk); | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static struct platform_driver dryice_rtc_driver = { | ||
496 | .driver = { | ||
497 | .name = "imxdi_rtc", | ||
498 | .owner = THIS_MODULE, | ||
499 | }, | ||
500 | .remove = __devexit_p(dryice_rtc_remove), | ||
501 | }; | ||
502 | |||
503 | static int __init dryice_rtc_init(void) | ||
504 | { | ||
505 | return platform_driver_probe(&dryice_rtc_driver, dryice_rtc_probe); | ||
506 | } | ||
507 | |||
508 | static void __exit dryice_rtc_exit(void) | ||
509 | { | ||
510 | platform_driver_unregister(&dryice_rtc_driver); | ||
511 | } | ||
512 | |||
513 | module_init(dryice_rtc_init); | ||
514 | module_exit(dryice_rtc_exit); | ||
515 | |||
516 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
517 | MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); | ||
518 | MODULE_DESCRIPTION("IMX DryIce Realtime Clock Driver (RTC)"); | ||
519 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c new file mode 100644 index 000000000000..ddbc797ea6cd --- /dev/null +++ b/drivers/rtc/rtc-isl12022.c | |||
@@ -0,0 +1,327 @@ | |||
1 | /* | ||
2 | * An I2C driver for the Intersil ISL 12022 | ||
3 | * | ||
4 | * Author: Roman Fietze <roman.fietze@telemotive.de> | ||
5 | * | ||
6 | * Based on the Philips PCF8563 RTC | ||
7 | * by Alessandro Zummo <a.zummo@towertech.it>. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/bcd.h> | ||
16 | #include <linux/rtc.h> | ||
17 | #include <linux/slab.h> | ||
18 | |||
19 | #define DRV_VERSION "0.1" | ||
20 | |||
21 | /* ISL register offsets */ | ||
22 | #define ISL12022_REG_SC 0x00 | ||
23 | #define ISL12022_REG_MN 0x01 | ||
24 | #define ISL12022_REG_HR 0x02 | ||
25 | #define ISL12022_REG_DT 0x03 | ||
26 | #define ISL12022_REG_MO 0x04 | ||
27 | #define ISL12022_REG_YR 0x05 | ||
28 | #define ISL12022_REG_DW 0x06 | ||
29 | |||
30 | #define ISL12022_REG_SR 0x07 | ||
31 | #define ISL12022_REG_INT 0x08 | ||
32 | |||
33 | /* ISL register bits */ | ||
34 | #define ISL12022_HR_MIL (1 << 7) /* military or 24 hour time */ | ||
35 | |||
36 | #define ISL12022_SR_LBAT85 (1 << 2) | ||
37 | #define ISL12022_SR_LBAT75 (1 << 1) | ||
38 | |||
39 | #define ISL12022_INT_WRTC (1 << 6) | ||
40 | |||
41 | |||
42 | static struct i2c_driver isl12022_driver; | ||
43 | |||
44 | struct isl12022 { | ||
45 | struct rtc_device *rtc; | ||
46 | |||
47 | bool write_enabled; /* true if write enable is set */ | ||
48 | }; | ||
49 | |||
50 | |||
51 | static int isl12022_read_regs(struct i2c_client *client, uint8_t reg, | ||
52 | uint8_t *data, size_t n) | ||
53 | { | ||
54 | struct i2c_msg msgs[] = { | ||
55 | { | ||
56 | .addr = client->addr, | ||
57 | .flags = 0, | ||
58 | .len = 1, | ||
59 | .buf = data | ||
60 | }, /* setup read ptr */ | ||
61 | { | ||
62 | .addr = client->addr, | ||
63 | .flags = I2C_M_RD, | ||
64 | .len = n, | ||
65 | .buf = data | ||
66 | } | ||
67 | }; | ||
68 | |||
69 | int ret; | ||
70 | |||
71 | data[0] = reg; | ||
72 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
73 | if (ret != ARRAY_SIZE(msgs)) { | ||
74 | dev_err(&client->dev, "%s: read error, ret=%d\n", | ||
75 | __func__, ret); | ||
76 | return -EIO; | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | |||
83 | static int isl12022_write_reg(struct i2c_client *client, | ||
84 | uint8_t reg, uint8_t val) | ||
85 | { | ||
86 | uint8_t data[2] = { reg, val }; | ||
87 | int err; | ||
88 | |||
89 | err = i2c_master_send(client, data, sizeof(data)); | ||
90 | if (err != sizeof(data)) { | ||
91 | dev_err(&client->dev, | ||
92 | "%s: err=%d addr=%02x, data=%02x\n", | ||
93 | __func__, err, data[0], data[1]); | ||
94 | return -EIO; | ||
95 | } | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | |||
101 | /* | ||
102 | * In the routines that deal directly with the isl12022 hardware, we use | ||
103 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. | ||
104 | */ | ||
105 | static int isl12022_get_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
106 | { | ||
107 | uint8_t buf[ISL12022_REG_INT + 1]; | ||
108 | int ret; | ||
109 | |||
110 | ret = isl12022_read_regs(client, ISL12022_REG_SC, buf, sizeof(buf)); | ||
111 | if (ret) | ||
112 | return ret; | ||
113 | |||
114 | if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) { | ||
115 | dev_warn(&client->dev, | ||
116 | "voltage dropped below %u%%, " | ||
117 | "date and time is not reliable.\n", | ||
118 | buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75); | ||
119 | } | ||
120 | |||
121 | dev_dbg(&client->dev, | ||
122 | "%s: raw data is sec=%02x, min=%02x, hr=%02x, " | ||
123 | "mday=%02x, mon=%02x, year=%02x, wday=%02x, " | ||
124 | "sr=%02x, int=%02x", | ||
125 | __func__, | ||
126 | buf[ISL12022_REG_SC], | ||
127 | buf[ISL12022_REG_MN], | ||
128 | buf[ISL12022_REG_HR], | ||
129 | buf[ISL12022_REG_DT], | ||
130 | buf[ISL12022_REG_MO], | ||
131 | buf[ISL12022_REG_YR], | ||
132 | buf[ISL12022_REG_DW], | ||
133 | buf[ISL12022_REG_SR], | ||
134 | buf[ISL12022_REG_INT]); | ||
135 | |||
136 | tm->tm_sec = bcd2bin(buf[ISL12022_REG_SC] & 0x7F); | ||
137 | tm->tm_min = bcd2bin(buf[ISL12022_REG_MN] & 0x7F); | ||
138 | tm->tm_hour = bcd2bin(buf[ISL12022_REG_HR] & 0x3F); | ||
139 | tm->tm_mday = bcd2bin(buf[ISL12022_REG_DT] & 0x3F); | ||
140 | tm->tm_wday = buf[ISL12022_REG_DW] & 0x07; | ||
141 | tm->tm_mon = bcd2bin(buf[ISL12022_REG_MO] & 0x1F) - 1; | ||
142 | tm->tm_year = bcd2bin(buf[ISL12022_REG_YR]) + 100; | ||
143 | |||
144 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " | ||
145 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
146 | __func__, | ||
147 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
148 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
149 | |||
150 | /* The clock can give out invalid datetime, but we cannot return | ||
151 | * -EINVAL otherwise hwclock will refuse to set the time on bootup. */ | ||
152 | if (rtc_valid_tm(tm) < 0) | ||
153 | dev_err(&client->dev, "retrieved date and time is invalid.\n"); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
159 | { | ||
160 | struct isl12022 *isl12022 = i2c_get_clientdata(client); | ||
161 | size_t i; | ||
162 | int ret; | ||
163 | uint8_t buf[ISL12022_REG_DW + 1]; | ||
164 | |||
165 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " | ||
166 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
167 | __func__, | ||
168 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
169 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
170 | |||
171 | if (!isl12022->write_enabled) { | ||
172 | |||
173 | ret = isl12022_read_regs(client, ISL12022_REG_INT, buf, 1); | ||
174 | if (ret) | ||
175 | return ret; | ||
176 | |||
177 | /* Check if WRTC (write rtc enable) is set factory default is | ||
178 | * 0 (not set) */ | ||
179 | if (!(buf[0] & ISL12022_INT_WRTC)) { | ||
180 | dev_info(&client->dev, | ||
181 | "init write enable and 24 hour format\n"); | ||
182 | |||
183 | /* Set the write enable bit. */ | ||
184 | ret = isl12022_write_reg(client, | ||
185 | ISL12022_REG_INT, | ||
186 | buf[0] | ISL12022_INT_WRTC); | ||
187 | if (ret) | ||
188 | return ret; | ||
189 | |||
190 | /* Write to any RTC register to start RTC, we use the | ||
191 | * HR register, setting the MIL bit to use the 24 hour | ||
192 | * format. */ | ||
193 | ret = isl12022_read_regs(client, ISL12022_REG_HR, | ||
194 | buf, 1); | ||
195 | if (ret) | ||
196 | return ret; | ||
197 | |||
198 | ret = isl12022_write_reg(client, | ||
199 | ISL12022_REG_HR, | ||
200 | buf[0] | ISL12022_HR_MIL); | ||
201 | if (ret) | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | isl12022->write_enabled = 1; | ||
206 | } | ||
207 | |||
208 | /* hours, minutes and seconds */ | ||
209 | buf[ISL12022_REG_SC] = bin2bcd(tm->tm_sec); | ||
210 | buf[ISL12022_REG_MN] = bin2bcd(tm->tm_min); | ||
211 | buf[ISL12022_REG_HR] = bin2bcd(tm->tm_hour) | ISL12022_HR_MIL; | ||
212 | |||
213 | buf[ISL12022_REG_DT] = bin2bcd(tm->tm_mday); | ||
214 | |||
215 | /* month, 1 - 12 */ | ||
216 | buf[ISL12022_REG_MO] = bin2bcd(tm->tm_mon + 1); | ||
217 | |||
218 | /* year and century */ | ||
219 | buf[ISL12022_REG_YR] = bin2bcd(tm->tm_year % 100); | ||
220 | |||
221 | buf[ISL12022_REG_DW] = tm->tm_wday & 0x07; | ||
222 | |||
223 | /* write register's data */ | ||
224 | for (i = 0; i < ARRAY_SIZE(buf); i++) { | ||
225 | ret = isl12022_write_reg(client, ISL12022_REG_SC + i, | ||
226 | buf[ISL12022_REG_SC + i]); | ||
227 | if (ret) | ||
228 | return -EIO; | ||
229 | }; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
235 | { | ||
236 | return isl12022_get_datetime(to_i2c_client(dev), tm); | ||
237 | } | ||
238 | |||
239 | static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
240 | { | ||
241 | return isl12022_set_datetime(to_i2c_client(dev), tm); | ||
242 | } | ||
243 | |||
244 | static const struct rtc_class_ops isl12022_rtc_ops = { | ||
245 | .read_time = isl12022_rtc_read_time, | ||
246 | .set_time = isl12022_rtc_set_time, | ||
247 | }; | ||
248 | |||
249 | static int isl12022_probe(struct i2c_client *client, | ||
250 | const struct i2c_device_id *id) | ||
251 | { | ||
252 | struct isl12022 *isl12022; | ||
253 | |||
254 | int ret = 0; | ||
255 | |||
256 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | ||
257 | return -ENODEV; | ||
258 | |||
259 | isl12022 = kzalloc(sizeof(struct isl12022), GFP_KERNEL); | ||
260 | if (!isl12022) | ||
261 | return -ENOMEM; | ||
262 | |||
263 | dev_dbg(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | ||
264 | |||
265 | i2c_set_clientdata(client, isl12022); | ||
266 | |||
267 | isl12022->rtc = rtc_device_register(isl12022_driver.driver.name, | ||
268 | &client->dev, | ||
269 | &isl12022_rtc_ops, | ||
270 | THIS_MODULE); | ||
271 | |||
272 | if (IS_ERR(isl12022->rtc)) { | ||
273 | ret = PTR_ERR(isl12022->rtc); | ||
274 | goto exit_kfree; | ||
275 | } | ||
276 | |||
277 | return 0; | ||
278 | |||
279 | exit_kfree: | ||
280 | kfree(isl12022); | ||
281 | |||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | static int isl12022_remove(struct i2c_client *client) | ||
286 | { | ||
287 | struct isl12022 *isl12022 = i2c_get_clientdata(client); | ||
288 | |||
289 | rtc_device_unregister(isl12022->rtc); | ||
290 | kfree(isl12022); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static const struct i2c_device_id isl12022_id[] = { | ||
296 | { "isl12022", 0 }, | ||
297 | { "rtc8564", 0 }, | ||
298 | { } | ||
299 | }; | ||
300 | MODULE_DEVICE_TABLE(i2c, isl12022_id); | ||
301 | |||
302 | static struct i2c_driver isl12022_driver = { | ||
303 | .driver = { | ||
304 | .name = "rtc-isl12022", | ||
305 | }, | ||
306 | .probe = isl12022_probe, | ||
307 | .remove = isl12022_remove, | ||
308 | .id_table = isl12022_id, | ||
309 | }; | ||
310 | |||
311 | static int __init isl12022_init(void) | ||
312 | { | ||
313 | return i2c_add_driver(&isl12022_driver); | ||
314 | } | ||
315 | |||
316 | static void __exit isl12022_exit(void) | ||
317 | { | ||
318 | i2c_del_driver(&isl12022_driver); | ||
319 | } | ||
320 | |||
321 | module_init(isl12022_init); | ||
322 | module_exit(isl12022_exit); | ||
323 | |||
324 | MODULE_AUTHOR("roman.fietze@telemotive.de"); | ||
325 | MODULE_DESCRIPTION("ISL 12022 RTC driver"); | ||
326 | MODULE_LICENSE("GPL"); | ||
327 | MODULE_VERSION(DRV_VERSION); | ||
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 6dc4e6241418..66377f3e28b8 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c | |||
@@ -121,7 +121,7 @@ static int m41t80_get_datetime(struct i2c_client *client, | |||
121 | 121 | ||
122 | /* assume 20YY not 19YY, and ignore the Century Bit */ | 122 | /* assume 20YY not 19YY, and ignore the Century Bit */ |
123 | tm->tm_year = bcd2bin(buf[M41T80_REG_YEAR]) + 100; | 123 | tm->tm_year = bcd2bin(buf[M41T80_REG_YEAR]) + 100; |
124 | return 0; | 124 | return rtc_valid_tm(tm); |
125 | } | 125 | } |
126 | 126 | ||
127 | /* Sets the given date and time to the real time clock. */ | 127 | /* Sets the given date and time to the real time clock. */ |
@@ -364,7 +364,7 @@ static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
364 | t->time.tm_isdst = -1; | 364 | t->time.tm_isdst = -1; |
365 | t->enabled = !!(reg[M41T80_REG_ALARM_MON] & M41T80_ALMON_AFE); | 365 | t->enabled = !!(reg[M41T80_REG_ALARM_MON] & M41T80_ALMON_AFE); |
366 | t->pending = !!(reg[M41T80_REG_FLAGS] & M41T80_FLAGS_AF); | 366 | t->pending = !!(reg[M41T80_REG_FLAGS] & M41T80_FLAGS_AF); |
367 | return 0; | 367 | return rtc_valid_tm(t); |
368 | } | 368 | } |
369 | 369 | ||
370 | static struct rtc_class_ops m41t80_rtc_ops = { | 370 | static struct rtc_class_ops m41t80_rtc_ops = { |
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index be8359fdb65a..a99a0b554eb8 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c | |||
@@ -105,7 +105,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
105 | dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d/%02d/%02d\n", | 105 | dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d/%02d/%02d\n", |
106 | tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, | 106 | tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, |
107 | tm->tm_hour, tm->tm_min, tm->tm_sec); | 107 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
108 | return 0; | 108 | return rtc_valid_tm(tm); |
109 | } | 109 | } |
110 | 110 | ||
111 | static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) | 111 | static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) |
@@ -196,7 +196,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
196 | dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d/%02d/%02d\n", | 196 | dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d/%02d/%02d\n", |
197 | tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, | 197 | tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, |
198 | tm->tm_hour, tm->tm_min, tm->tm_sec); | 198 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
199 | return 0; | 199 | return rtc_valid_tm(tm); |
200 | } | 200 | } |
201 | 201 | ||
202 | /* | 202 | /* |
@@ -506,7 +506,6 @@ out: | |||
506 | free_irq(m48t59->irq, &pdev->dev); | 506 | free_irq(m48t59->irq, &pdev->dev); |
507 | if (m48t59->ioaddr) | 507 | if (m48t59->ioaddr) |
508 | iounmap(m48t59->ioaddr); | 508 | iounmap(m48t59->ioaddr); |
509 | if (m48t59) | ||
510 | kfree(m48t59); | 509 | kfree(m48t59); |
511 | return ret; | 510 | return ret; |
512 | } | 511 | } |
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 7c045cffa9ff..f981287d582b 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c | |||
@@ -77,7 +77,7 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
77 | if (ops->readbyte(M48T86_REG_HOUR) & 0x80) | 77 | if (ops->readbyte(M48T86_REG_HOUR) & 0x80) |
78 | tm->tm_hour += 12; | 78 | tm->tm_hour += 12; |
79 | 79 | ||
80 | return 0; | 80 | return rtc_valid_tm(tm); |
81 | } | 81 | } |
82 | 82 | ||
83 | static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) | 83 | static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) |
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index a4f6665ab3c5..486142c2637a 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c | |||
@@ -159,7 +159,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) | |||
159 | bcd2bin(regs[MAX6900_REG_CENTURY]) * 100 - 1900; | 159 | bcd2bin(regs[MAX6900_REG_CENTURY]) * 100 - 1900; |
160 | tm->tm_wday = bcd2bin(regs[MAX6900_REG_DW]); | 160 | tm->tm_wday = bcd2bin(regs[MAX6900_REG_DW]); |
161 | 161 | ||
162 | return 0; | 162 | return rtc_valid_tm(tm); |
163 | } | 163 | } |
164 | 164 | ||
165 | static int max6900_i2c_clear_write_protect(struct i2c_client *client) | 165 | static int max6900_i2c_clear_write_protect(struct i2c_client *client) |
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 25ec921db07c..0b06c1e03fd5 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c | |||
@@ -83,12 +83,6 @@ struct rtc_plat_data { | |||
83 | void __iomem *ioaddr; | 83 | void __iomem *ioaddr; |
84 | int irq; | 84 | int irq; |
85 | struct clk *clk; | 85 | struct clk *clk; |
86 | unsigned int irqen; | ||
87 | int alrm_sec; | ||
88 | int alrm_min; | ||
89 | int alrm_hour; | ||
90 | int alrm_mday; | ||
91 | struct timespec mxc_rtc_delta; | ||
92 | struct rtc_time g_rtc_alarm; | 86 | struct rtc_time g_rtc_alarm; |
93 | }; | 87 | }; |
94 | 88 | ||
diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index a351bd5d8176..62de66af0a68 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c | |||
@@ -85,25 +85,24 @@ static irqreturn_t nuc900_rtc_interrupt(int irq, void *_rtc) | |||
85 | 85 | ||
86 | static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc) | 86 | static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc) |
87 | { | 87 | { |
88 | unsigned int i; | 88 | unsigned int timeout = 0x1000; |
89 | __raw_writel(INIRRESET, nuc900_rtc->rtc_reg + REG_RTC_INIR); | 89 | __raw_writel(INIRRESET, nuc900_rtc->rtc_reg + REG_RTC_INIR); |
90 | 90 | ||
91 | mdelay(10); | 91 | mdelay(10); |
92 | 92 | ||
93 | __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER); | 93 | __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER); |
94 | 94 | ||
95 | for (i = 0; i < 1000; i++) { | 95 | while (!(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) |
96 | if (__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) | 96 | && timeout--) |
97 | return 0; | 97 | mdelay(1); |
98 | } | ||
99 | 98 | ||
100 | if ((__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) == 0x0) | 99 | if (!timeout) |
101 | return ERR_PTR(-ENODEV); | 100 | return ERR_PTR(-EPERM); |
102 | 101 | ||
103 | return ERR_PTR(-EPERM); | 102 | return 0; |
104 | } | 103 | } |
105 | 104 | ||
106 | static void nuc900_rtc_bcd2bin(unsigned int timereg, | 105 | static int nuc900_rtc_bcd2bin(unsigned int timereg, |
107 | unsigned int calreg, struct rtc_time *tm) | 106 | unsigned int calreg, struct rtc_time *tm) |
108 | { | 107 | { |
109 | tm->tm_mday = bcd2bin(calreg >> 0); | 108 | tm->tm_mday = bcd2bin(calreg >> 0); |
@@ -114,15 +113,21 @@ static void nuc900_rtc_bcd2bin(unsigned int timereg, | |||
114 | tm->tm_min = bcd2bin(timereg >> 8); | 113 | tm->tm_min = bcd2bin(timereg >> 8); |
115 | tm->tm_hour = bcd2bin(timereg >> 16); | 114 | tm->tm_hour = bcd2bin(timereg >> 16); |
116 | 115 | ||
117 | rtc_valid_tm(tm); | 116 | return rtc_valid_tm(tm); |
118 | } | 117 | } |
119 | 118 | ||
120 | static void nuc900_rtc_bin2bcd(struct rtc_time *settm, | 119 | static void nuc900_rtc_bin2bcd(struct device *dev, struct rtc_time *settm, |
121 | struct nuc900_bcd_time *gettm) | 120 | struct nuc900_bcd_time *gettm) |
122 | { | 121 | { |
123 | gettm->bcd_mday = bin2bcd(settm->tm_mday) << 0; | 122 | gettm->bcd_mday = bin2bcd(settm->tm_mday) << 0; |
124 | gettm->bcd_mon = bin2bcd(settm->tm_mon) << 8; | 123 | gettm->bcd_mon = bin2bcd(settm->tm_mon) << 8; |
125 | gettm->bcd_year = bin2bcd(settm->tm_year - 100) << 16; | 124 | |
125 | if (settm->tm_year < 100) { | ||
126 | dev_warn(dev, "The year will be between 1970-1999, right?\n"); | ||
127 | gettm->bcd_year = bin2bcd(settm->tm_year) << 16; | ||
128 | } else { | ||
129 | gettm->bcd_year = bin2bcd(settm->tm_year - 100) << 16; | ||
130 | } | ||
126 | 131 | ||
127 | gettm->bcd_sec = bin2bcd(settm->tm_sec) << 0; | 132 | gettm->bcd_sec = bin2bcd(settm->tm_sec) << 0; |
128 | gettm->bcd_min = bin2bcd(settm->tm_min) << 8; | 133 | gettm->bcd_min = bin2bcd(settm->tm_min) << 8; |
@@ -165,9 +170,7 @@ static int nuc900_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
165 | timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TLR); | 170 | timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TLR); |
166 | clrval = __raw_readl(rtc->rtc_reg + REG_RTC_CLR); | 171 | clrval = __raw_readl(rtc->rtc_reg + REG_RTC_CLR); |
167 | 172 | ||
168 | nuc900_rtc_bcd2bin(timeval, clrval, tm); | 173 | return nuc900_rtc_bcd2bin(timeval, clrval, tm); |
169 | |||
170 | return 0; | ||
171 | } | 174 | } |
172 | 175 | ||
173 | static int nuc900_rtc_set_time(struct device *dev, struct rtc_time *tm) | 176 | static int nuc900_rtc_set_time(struct device *dev, struct rtc_time *tm) |
@@ -177,7 +180,7 @@ static int nuc900_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
177 | unsigned long val; | 180 | unsigned long val; |
178 | int *err; | 181 | int *err; |
179 | 182 | ||
180 | nuc900_rtc_bin2bcd(tm, &gettm); | 183 | nuc900_rtc_bin2bcd(dev, tm, &gettm); |
181 | 184 | ||
182 | err = check_rtc_access_enable(rtc); | 185 | err = check_rtc_access_enable(rtc); |
183 | if (IS_ERR(err)) | 186 | if (IS_ERR(err)) |
@@ -200,9 +203,7 @@ static int nuc900_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
200 | timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TAR); | 203 | timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TAR); |
201 | carval = __raw_readl(rtc->rtc_reg + REG_RTC_CAR); | 204 | carval = __raw_readl(rtc->rtc_reg + REG_RTC_CAR); |
202 | 205 | ||
203 | nuc900_rtc_bcd2bin(timeval, carval, &alrm->time); | 206 | return nuc900_rtc_bcd2bin(timeval, carval, &alrm->time); |
204 | |||
205 | return 0; | ||
206 | } | 207 | } |
207 | 208 | ||
208 | static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 209 | static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
@@ -212,7 +213,7 @@ static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
212 | unsigned long val; | 213 | unsigned long val; |
213 | int *err; | 214 | int *err; |
214 | 215 | ||
215 | nuc900_rtc_bin2bcd(&alrm->time, &tm); | 216 | nuc900_rtc_bin2bcd(dev, &alrm->time, &tm); |
216 | 217 | ||
217 | err = check_rtc_access_enable(rtc); | 218 | err = check_rtc_access_enable(rtc); |
218 | if (IS_ERR(err)) | 219 | if (IS_ERR(err)) |
@@ -268,29 +269,30 @@ static int __devinit nuc900_rtc_probe(struct platform_device *pdev) | |||
268 | goto fail2; | 269 | goto fail2; |
269 | } | 270 | } |
270 | 271 | ||
271 | nuc900_rtc->irq_num = platform_get_irq(pdev, 0); | 272 | platform_set_drvdata(pdev, nuc900_rtc); |
272 | if (request_irq(nuc900_rtc->irq_num, nuc900_rtc_interrupt, | ||
273 | IRQF_DISABLED, "nuc900rtc", nuc900_rtc)) { | ||
274 | dev_err(&pdev->dev, "NUC900 RTC request irq failed\n"); | ||
275 | err = -EBUSY; | ||
276 | goto fail3; | ||
277 | } | ||
278 | 273 | ||
279 | nuc900_rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev, | 274 | nuc900_rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev, |
280 | &nuc900_rtc_ops, THIS_MODULE); | 275 | &nuc900_rtc_ops, THIS_MODULE); |
281 | if (IS_ERR(nuc900_rtc->rtcdev)) { | 276 | if (IS_ERR(nuc900_rtc->rtcdev)) { |
282 | dev_err(&pdev->dev, "rtc device register faild\n"); | 277 | dev_err(&pdev->dev, "rtc device register faild\n"); |
283 | err = PTR_ERR(nuc900_rtc->rtcdev); | 278 | err = PTR_ERR(nuc900_rtc->rtcdev); |
284 | goto fail4; | 279 | goto fail3; |
285 | } | 280 | } |
286 | 281 | ||
287 | platform_set_drvdata(pdev, nuc900_rtc); | ||
288 | __raw_writel(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_TSSR) | MODE24, | 282 | __raw_writel(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_TSSR) | MODE24, |
289 | nuc900_rtc->rtc_reg + REG_RTC_TSSR); | 283 | nuc900_rtc->rtc_reg + REG_RTC_TSSR); |
290 | 284 | ||
285 | nuc900_rtc->irq_num = platform_get_irq(pdev, 0); | ||
286 | if (request_irq(nuc900_rtc->irq_num, nuc900_rtc_interrupt, | ||
287 | IRQF_DISABLED, "nuc900rtc", nuc900_rtc)) { | ||
288 | dev_err(&pdev->dev, "NUC900 RTC request irq failed\n"); | ||
289 | err = -EBUSY; | ||
290 | goto fail4; | ||
291 | } | ||
292 | |||
291 | return 0; | 293 | return 0; |
292 | 294 | ||
293 | fail4: free_irq(nuc900_rtc->irq_num, nuc900_rtc); | 295 | fail4: rtc_device_unregister(nuc900_rtc->rtcdev); |
294 | fail3: iounmap(nuc900_rtc->rtc_reg); | 296 | fail3: iounmap(nuc900_rtc->rtc_reg); |
295 | fail2: release_mem_region(res->start, resource_size(res)); | 297 | fail2: release_mem_region(res->start, resource_size(res)); |
296 | fail1: kfree(nuc900_rtc); | 298 | fail1: kfree(nuc900_rtc); |
@@ -302,8 +304,8 @@ static int __devexit nuc900_rtc_remove(struct platform_device *pdev) | |||
302 | struct nuc900_rtc *nuc900_rtc = platform_get_drvdata(pdev); | 304 | struct nuc900_rtc *nuc900_rtc = platform_get_drvdata(pdev); |
303 | struct resource *res; | 305 | struct resource *res; |
304 | 306 | ||
305 | rtc_device_unregister(nuc900_rtc->rtcdev); | ||
306 | free_irq(nuc900_rtc->irq_num, nuc900_rtc); | 307 | free_irq(nuc900_rtc->irq_num, nuc900_rtc); |
308 | rtc_device_unregister(nuc900_rtc->rtcdev); | ||
307 | iounmap(nuc900_rtc->rtc_reg); | 309 | iounmap(nuc900_rtc->rtc_reg); |
308 | 310 | ||
309 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 311 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 1af42b4a6f59..b42c0c679266 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c | |||
@@ -172,14 +172,6 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) | |||
172 | return 0; | 172 | return 0; |
173 | } | 173 | } |
174 | 174 | ||
175 | struct pcf8563_limit | ||
176 | { | ||
177 | unsigned char reg; | ||
178 | unsigned char mask; | ||
179 | unsigned char min; | ||
180 | unsigned char max; | ||
181 | }; | ||
182 | |||
183 | static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) | 175 | static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) |
184 | { | 176 | { |
185 | return pcf8563_get_datetime(to_i2c_client(dev), tm); | 177 | return pcf8563_get_datetime(to_i2c_client(dev), tm); |
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 71bbefc3544e..6c418fe7f288 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/bcd.h> | 24 | #include <linux/bcd.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/version.h> | ||
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
28 | 27 | ||
29 | /* | 28 | /* |
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index e9c6fa035989..29e867a1aaa8 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c | |||
@@ -87,7 +87,6 @@ struct pxa_rtc { | |||
87 | int irq_Alrm; | 87 | int irq_Alrm; |
88 | struct rtc_device *rtc; | 88 | struct rtc_device *rtc; |
89 | spinlock_t lock; /* Protects this structure */ | 89 | spinlock_t lock; /* Protects this structure */ |
90 | struct rtc_time rtc_alarm; | ||
91 | }; | 90 | }; |
92 | 91 | ||
93 | static u32 ryxr_calc(struct rtc_time *tm) | 92 | static u32 ryxr_calc(struct rtc_time *tm) |
@@ -236,32 +235,34 @@ static int pxa_periodic_irq_set_state(struct device *dev, int enabled) | |||
236 | return 0; | 235 | return 0; |
237 | } | 236 | } |
238 | 237 | ||
239 | static int pxa_rtc_ioctl(struct device *dev, unsigned int cmd, | 238 | static int pxa_alarm_irq_enable(struct device *dev, unsigned int enabled) |
240 | unsigned long arg) | ||
241 | { | 239 | { |
242 | struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); | 240 | struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); |
243 | int ret = 0; | ||
244 | 241 | ||
245 | spin_lock_irq(&pxa_rtc->lock); | 242 | spin_lock_irq(&pxa_rtc->lock); |
246 | switch (cmd) { | 243 | |
247 | case RTC_AIE_OFF: | 244 | if (enabled) |
248 | rtsr_clear_bits(pxa_rtc, RTSR_RDALE1); | ||
249 | break; | ||
250 | case RTC_AIE_ON: | ||
251 | rtsr_set_bits(pxa_rtc, RTSR_RDALE1); | 245 | rtsr_set_bits(pxa_rtc, RTSR_RDALE1); |
252 | break; | 246 | else |
253 | case RTC_UIE_OFF: | 247 | rtsr_clear_bits(pxa_rtc, RTSR_RDALE1); |
254 | rtsr_clear_bits(pxa_rtc, RTSR_HZE); | 248 | |
255 | break; | 249 | spin_unlock_irq(&pxa_rtc->lock); |
256 | case RTC_UIE_ON: | 250 | return 0; |
251 | } | ||
252 | |||
253 | static int pxa_update_irq_enable(struct device *dev, unsigned int enabled) | ||
254 | { | ||
255 | struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); | ||
256 | |||
257 | spin_lock_irq(&pxa_rtc->lock); | ||
258 | |||
259 | if (enabled) | ||
257 | rtsr_set_bits(pxa_rtc, RTSR_HZE); | 260 | rtsr_set_bits(pxa_rtc, RTSR_HZE); |
258 | break; | 261 | else |
259 | default: | 262 | rtsr_clear_bits(pxa_rtc, RTSR_HZE); |
260 | ret = -ENOIOCTLCMD; | ||
261 | } | ||
262 | 263 | ||
263 | spin_unlock_irq(&pxa_rtc->lock); | 264 | spin_unlock_irq(&pxa_rtc->lock); |
264 | return ret; | 265 | return 0; |
265 | } | 266 | } |
266 | 267 | ||
267 | static int pxa_rtc_read_time(struct device *dev, struct rtc_time *tm) | 268 | static int pxa_rtc_read_time(struct device *dev, struct rtc_time *tm) |
@@ -340,11 +341,12 @@ static int pxa_rtc_proc(struct device *dev, struct seq_file *seq) | |||
340 | static const struct rtc_class_ops pxa_rtc_ops = { | 341 | static const struct rtc_class_ops pxa_rtc_ops = { |
341 | .open = pxa_rtc_open, | 342 | .open = pxa_rtc_open, |
342 | .release = pxa_rtc_release, | 343 | .release = pxa_rtc_release, |
343 | .ioctl = pxa_rtc_ioctl, | ||
344 | .read_time = pxa_rtc_read_time, | 344 | .read_time = pxa_rtc_read_time, |
345 | .set_time = pxa_rtc_set_time, | 345 | .set_time = pxa_rtc_set_time, |
346 | .read_alarm = pxa_rtc_read_alarm, | 346 | .read_alarm = pxa_rtc_read_alarm, |
347 | .set_alarm = pxa_rtc_set_alarm, | 347 | .set_alarm = pxa_rtc_set_alarm, |
348 | .alarm_irq_enable = pxa_alarm_irq_enable, | ||
349 | .update_irq_enable = pxa_update_irq_enable, | ||
348 | .proc = pxa_rtc_proc, | 350 | .proc = pxa_rtc_proc, |
349 | .irq_set_state = pxa_periodic_irq_set_state, | 351 | .irq_set_state = pxa_periodic_irq_set_state, |
350 | .irq_set_freq = pxa_periodic_irq_set_freq, | 352 | .irq_set_freq = pxa_periodic_irq_set_freq, |
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index a95f733bb15a..36eb66184461 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c | |||
@@ -63,6 +63,8 @@ enum { | |||
63 | struct rp5c01_priv { | 63 | struct rp5c01_priv { |
64 | u32 __iomem *regs; | 64 | u32 __iomem *regs; |
65 | struct rtc_device *rtc; | 65 | struct rtc_device *rtc; |
66 | spinlock_t lock; /* against concurrent RTC/NVRAM access */ | ||
67 | struct bin_attribute nvram_attr; | ||
66 | }; | 68 | }; |
67 | 69 | ||
68 | static inline unsigned int rp5c01_read(struct rp5c01_priv *priv, | 70 | static inline unsigned int rp5c01_read(struct rp5c01_priv *priv, |
@@ -92,6 +94,7 @@ static int rp5c01_read_time(struct device *dev, struct rtc_time *tm) | |||
92 | { | 94 | { |
93 | struct rp5c01_priv *priv = dev_get_drvdata(dev); | 95 | struct rp5c01_priv *priv = dev_get_drvdata(dev); |
94 | 96 | ||
97 | spin_lock_irq(&priv->lock); | ||
95 | rp5c01_lock(priv); | 98 | rp5c01_lock(priv); |
96 | 99 | ||
97 | tm->tm_sec = rp5c01_read(priv, RP5C01_10_SECOND) * 10 + | 100 | tm->tm_sec = rp5c01_read(priv, RP5C01_10_SECOND) * 10 + |
@@ -111,6 +114,7 @@ static int rp5c01_read_time(struct device *dev, struct rtc_time *tm) | |||
111 | tm->tm_year += 100; | 114 | tm->tm_year += 100; |
112 | 115 | ||
113 | rp5c01_unlock(priv); | 116 | rp5c01_unlock(priv); |
117 | spin_unlock_irq(&priv->lock); | ||
114 | 118 | ||
115 | return rtc_valid_tm(tm); | 119 | return rtc_valid_tm(tm); |
116 | } | 120 | } |
@@ -119,6 +123,7 @@ static int rp5c01_set_time(struct device *dev, struct rtc_time *tm) | |||
119 | { | 123 | { |
120 | struct rp5c01_priv *priv = dev_get_drvdata(dev); | 124 | struct rp5c01_priv *priv = dev_get_drvdata(dev); |
121 | 125 | ||
126 | spin_lock_irq(&priv->lock); | ||
122 | rp5c01_lock(priv); | 127 | rp5c01_lock(priv); |
123 | 128 | ||
124 | rp5c01_write(priv, tm->tm_sec / 10, RP5C01_10_SECOND); | 129 | rp5c01_write(priv, tm->tm_sec / 10, RP5C01_10_SECOND); |
@@ -139,6 +144,7 @@ static int rp5c01_set_time(struct device *dev, struct rtc_time *tm) | |||
139 | rp5c01_write(priv, tm->tm_year % 10, RP5C01_1_YEAR); | 144 | rp5c01_write(priv, tm->tm_year % 10, RP5C01_1_YEAR); |
140 | 145 | ||
141 | rp5c01_unlock(priv); | 146 | rp5c01_unlock(priv); |
147 | spin_unlock_irq(&priv->lock); | ||
142 | return 0; | 148 | return 0; |
143 | } | 149 | } |
144 | 150 | ||
@@ -147,6 +153,72 @@ static const struct rtc_class_ops rp5c01_rtc_ops = { | |||
147 | .set_time = rp5c01_set_time, | 153 | .set_time = rp5c01_set_time, |
148 | }; | 154 | }; |
149 | 155 | ||
156 | |||
157 | /* | ||
158 | * The NVRAM is organized as 2 blocks of 13 nibbles of 4 bits. | ||
159 | * We provide access to them like AmigaOS does: the high nibble of each 8-bit | ||
160 | * byte is stored in BLOCK10, the low nibble in BLOCK11. | ||
161 | */ | ||
162 | |||
163 | static ssize_t rp5c01_nvram_read(struct file *filp, struct kobject *kobj, | ||
164 | struct bin_attribute *bin_attr, | ||
165 | char *buf, loff_t pos, size_t size) | ||
166 | { | ||
167 | struct device *dev = container_of(kobj, struct device, kobj); | ||
168 | struct rp5c01_priv *priv = dev_get_drvdata(dev); | ||
169 | ssize_t count; | ||
170 | |||
171 | spin_lock_irq(&priv->lock); | ||
172 | |||
173 | for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) { | ||
174 | u8 data; | ||
175 | |||
176 | rp5c01_write(priv, | ||
177 | RP5C01_MODE_TIMER_EN | RP5C01_MODE_RAM_BLOCK10, | ||
178 | RP5C01_MODE); | ||
179 | data = rp5c01_read(priv, pos) << 4; | ||
180 | rp5c01_write(priv, | ||
181 | RP5C01_MODE_TIMER_EN | RP5C01_MODE_RAM_BLOCK11, | ||
182 | RP5C01_MODE); | ||
183 | data |= rp5c01_read(priv, pos++); | ||
184 | rp5c01_write(priv, RP5C01_MODE_TIMER_EN | RP5C01_MODE_MODE01, | ||
185 | RP5C01_MODE); | ||
186 | *buf++ = data; | ||
187 | } | ||
188 | |||
189 | spin_unlock_irq(&priv->lock); | ||
190 | return count; | ||
191 | } | ||
192 | |||
193 | static ssize_t rp5c01_nvram_write(struct file *filp, struct kobject *kobj, | ||
194 | struct bin_attribute *bin_attr, | ||
195 | char *buf, loff_t pos, size_t size) | ||
196 | { | ||
197 | struct device *dev = container_of(kobj, struct device, kobj); | ||
198 | struct rp5c01_priv *priv = dev_get_drvdata(dev); | ||
199 | ssize_t count; | ||
200 | |||
201 | spin_lock_irq(&priv->lock); | ||
202 | |||
203 | for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) { | ||
204 | u8 data = *buf++; | ||
205 | |||
206 | rp5c01_write(priv, | ||
207 | RP5C01_MODE_TIMER_EN | RP5C01_MODE_RAM_BLOCK10, | ||
208 | RP5C01_MODE); | ||
209 | rp5c01_write(priv, data >> 4, pos); | ||
210 | rp5c01_write(priv, | ||
211 | RP5C01_MODE_TIMER_EN | RP5C01_MODE_RAM_BLOCK11, | ||
212 | RP5C01_MODE); | ||
213 | rp5c01_write(priv, data & 0xf, pos++); | ||
214 | rp5c01_write(priv, RP5C01_MODE_TIMER_EN | RP5C01_MODE_MODE01, | ||
215 | RP5C01_MODE); | ||
216 | } | ||
217 | |||
218 | spin_unlock_irq(&priv->lock); | ||
219 | return count; | ||
220 | } | ||
221 | |||
150 | static int __init rp5c01_rtc_probe(struct platform_device *dev) | 222 | static int __init rp5c01_rtc_probe(struct platform_device *dev) |
151 | { | 223 | { |
152 | struct resource *res; | 224 | struct resource *res; |
@@ -168,6 +240,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) | |||
168 | goto out_free_priv; | 240 | goto out_free_priv; |
169 | } | 241 | } |
170 | 242 | ||
243 | sysfs_bin_attr_init(&priv->nvram_attr); | ||
244 | priv->nvram_attr.attr.name = "nvram"; | ||
245 | priv->nvram_attr.attr.mode = S_IRUGO | S_IWUSR; | ||
246 | priv->nvram_attr.read = rp5c01_nvram_read; | ||
247 | priv->nvram_attr.write = rp5c01_nvram_write; | ||
248 | priv->nvram_attr.size = RP5C01_MODE; | ||
249 | |||
250 | spin_lock_init(&priv->lock); | ||
251 | |||
171 | rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops, | 252 | rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops, |
172 | THIS_MODULE); | 253 | THIS_MODULE); |
173 | if (IS_ERR(rtc)) { | 254 | if (IS_ERR(rtc)) { |
@@ -177,8 +258,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) | |||
177 | 258 | ||
178 | priv->rtc = rtc; | 259 | priv->rtc = rtc; |
179 | platform_set_drvdata(dev, priv); | 260 | platform_set_drvdata(dev, priv); |
261 | |||
262 | error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr); | ||
263 | if (error) | ||
264 | goto out_unregister; | ||
265 | |||
180 | return 0; | 266 | return 0; |
181 | 267 | ||
268 | out_unregister: | ||
269 | rtc_device_unregister(rtc); | ||
182 | out_unmap: | 270 | out_unmap: |
183 | iounmap(priv->regs); | 271 | iounmap(priv->regs); |
184 | out_free_priv: | 272 | out_free_priv: |
@@ -190,6 +278,7 @@ static int __exit rp5c01_rtc_remove(struct platform_device *dev) | |||
190 | { | 278 | { |
191 | struct rp5c01_priv *priv = platform_get_drvdata(dev); | 279 | struct rp5c01_priv *priv = platform_get_drvdata(dev); |
192 | 280 | ||
281 | sysfs_remove_bin_file(&dev->dev.kobj, &priv->nvram_attr); | ||
193 | rtc_device_unregister(priv->rtc); | 282 | rtc_device_unregister(priv->rtc); |
194 | iounmap(priv->regs); | 283 | iounmap(priv->regs); |
195 | kfree(priv); | 284 | kfree(priv); |