diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
commit | 7a9787e1eba95a166265e6a260cf30af04ef0a99 (patch) | |
tree | e730a4565e0318140d2fbd2f0415d18a339d7336 /drivers/rtc/rtc-m48t59.c | |
parent | 41b9eb264c8407655db57b60b4457fe1b2ec9977 (diff) | |
parent | 0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff) |
Merge commit 'v2.6.28-rc2' into x86/pci-ioapic-boot-irq-quirks
Diffstat (limited to 'drivers/rtc/rtc-m48t59.c')
-rw-r--r-- | drivers/rtc/rtc-m48t59.c | 117 |
1 files changed, 76 insertions, 41 deletions
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 013e6c103b9c..04b63dab6932 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c | |||
@@ -24,8 +24,9 @@ | |||
24 | #define NO_IRQ (-1) | 24 | #define NO_IRQ (-1) |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | #define M48T59_READ(reg) pdata->read_byte(dev, reg) | 27 | #define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg)) |
28 | #define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val) | 28 | #define M48T59_WRITE(val, reg) \ |
29 | (pdata->write_byte(dev, pdata->offset + reg, val)) | ||
29 | 30 | ||
30 | #define M48T59_SET_BITS(mask, reg) \ | 31 | #define M48T59_SET_BITS(mask, reg) \ |
31 | M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg)) | 32 | M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg)) |
@@ -34,7 +35,6 @@ | |||
34 | 35 | ||
35 | struct m48t59_private { | 36 | struct m48t59_private { |
36 | void __iomem *ioaddr; | 37 | void __iomem *ioaddr; |
37 | unsigned int size; /* iomem size */ | ||
38 | int irq; | 38 | int irq; |
39 | struct rtc_device *rtc; | 39 | struct rtc_device *rtc; |
40 | spinlock_t lock; /* serialize the NVRAM and RTC access */ | 40 | spinlock_t lock; /* serialize the NVRAM and RTC access */ |
@@ -76,21 +76,22 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
76 | /* Issue the READ command */ | 76 | /* Issue the READ command */ |
77 | M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); | 77 | M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); |
78 | 78 | ||
79 | tm->tm_year = BCD2BIN(M48T59_READ(M48T59_YEAR)); | 79 | tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)); |
80 | /* tm_mon is 0-11 */ | 80 | /* tm_mon is 0-11 */ |
81 | tm->tm_mon = BCD2BIN(M48T59_READ(M48T59_MONTH)) - 1; | 81 | tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; |
82 | tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_MDAY)); | 82 | tm->tm_mday = bcd2bin(M48T59_READ(M48T59_MDAY)); |
83 | 83 | ||
84 | val = M48T59_READ(M48T59_WDAY); | 84 | val = M48T59_READ(M48T59_WDAY); |
85 | if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { | 85 | if ((pdata->type == M48T59RTC_TYPE_M48T59) && |
86 | (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { | ||
86 | dev_dbg(dev, "Century bit is enabled\n"); | 87 | dev_dbg(dev, "Century bit is enabled\n"); |
87 | tm->tm_year += 100; /* one century */ | 88 | tm->tm_year += 100; /* one century */ |
88 | } | 89 | } |
89 | 90 | ||
90 | tm->tm_wday = BCD2BIN(val & 0x07); | 91 | tm->tm_wday = bcd2bin(val & 0x07); |
91 | tm->tm_hour = BCD2BIN(M48T59_READ(M48T59_HOUR) & 0x3F); | 92 | tm->tm_hour = bcd2bin(M48T59_READ(M48T59_HOUR) & 0x3F); |
92 | tm->tm_min = BCD2BIN(M48T59_READ(M48T59_MIN) & 0x7F); | 93 | tm->tm_min = bcd2bin(M48T59_READ(M48T59_MIN) & 0x7F); |
93 | tm->tm_sec = BCD2BIN(M48T59_READ(M48T59_SEC) & 0x7F); | 94 | tm->tm_sec = bcd2bin(M48T59_READ(M48T59_SEC) & 0x7F); |
94 | 95 | ||
95 | /* Clear the READ bit */ | 96 | /* Clear the READ bit */ |
96 | M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); | 97 | M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); |
@@ -118,17 +119,17 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
118 | /* Issue the WRITE command */ | 119 | /* Issue the WRITE command */ |
119 | M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); | 120 | M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); |
120 | 121 | ||
121 | M48T59_WRITE((BIN2BCD(tm->tm_sec) & 0x7F), M48T59_SEC); | 122 | M48T59_WRITE((bin2bcd(tm->tm_sec) & 0x7F), M48T59_SEC); |
122 | M48T59_WRITE((BIN2BCD(tm->tm_min) & 0x7F), M48T59_MIN); | 123 | M48T59_WRITE((bin2bcd(tm->tm_min) & 0x7F), M48T59_MIN); |
123 | M48T59_WRITE((BIN2BCD(tm->tm_hour) & 0x3F), M48T59_HOUR); | 124 | M48T59_WRITE((bin2bcd(tm->tm_hour) & 0x3F), M48T59_HOUR); |
124 | M48T59_WRITE((BIN2BCD(tm->tm_mday) & 0x3F), M48T59_MDAY); | 125 | M48T59_WRITE((bin2bcd(tm->tm_mday) & 0x3F), M48T59_MDAY); |
125 | /* tm_mon is 0-11 */ | 126 | /* tm_mon is 0-11 */ |
126 | M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH); | 127 | M48T59_WRITE((bin2bcd(tm->tm_mon + 1) & 0x1F), M48T59_MONTH); |
127 | M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR); | 128 | M48T59_WRITE(bin2bcd(tm->tm_year % 100), M48T59_YEAR); |
128 | 129 | ||
129 | if (tm->tm_year/100) | 130 | if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100)) |
130 | val = (M48T59_WDAY_CEB | M48T59_WDAY_CB); | 131 | val = (M48T59_WDAY_CEB | M48T59_WDAY_CB); |
131 | val |= (BIN2BCD(tm->tm_wday) & 0x07); | 132 | val |= (bin2bcd(tm->tm_wday) & 0x07); |
132 | M48T59_WRITE(val, M48T59_WDAY); | 133 | M48T59_WRITE(val, M48T59_WDAY); |
133 | 134 | ||
134 | /* Clear the WRITE bit */ | 135 | /* Clear the WRITE bit */ |
@@ -157,18 +158,18 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
157 | /* Issue the READ command */ | 158 | /* Issue the READ command */ |
158 | M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); | 159 | M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); |
159 | 160 | ||
160 | tm->tm_year = BCD2BIN(M48T59_READ(M48T59_YEAR)); | 161 | tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)); |
161 | /* tm_mon is 0-11 */ | 162 | /* tm_mon is 0-11 */ |
162 | tm->tm_mon = BCD2BIN(M48T59_READ(M48T59_MONTH)) - 1; | 163 | tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; |
163 | 164 | ||
164 | val = M48T59_READ(M48T59_WDAY); | 165 | val = M48T59_READ(M48T59_WDAY); |
165 | if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) | 166 | if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) |
166 | tm->tm_year += 100; /* one century */ | 167 | tm->tm_year += 100; /* one century */ |
167 | 168 | ||
168 | tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_ALARM_DATE)); | 169 | tm->tm_mday = bcd2bin(M48T59_READ(M48T59_ALARM_DATE)); |
169 | tm->tm_hour = BCD2BIN(M48T59_READ(M48T59_ALARM_HOUR)); | 170 | tm->tm_hour = bcd2bin(M48T59_READ(M48T59_ALARM_HOUR)); |
170 | tm->tm_min = BCD2BIN(M48T59_READ(M48T59_ALARM_MIN)); | 171 | tm->tm_min = bcd2bin(M48T59_READ(M48T59_ALARM_MIN)); |
171 | tm->tm_sec = BCD2BIN(M48T59_READ(M48T59_ALARM_SEC)); | 172 | tm->tm_sec = bcd2bin(M48T59_READ(M48T59_ALARM_SEC)); |
172 | 173 | ||
173 | /* Clear the READ bit */ | 174 | /* Clear the READ bit */ |
174 | M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); | 175 | M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); |
@@ -200,18 +201,18 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
200 | * 0xff means "always match" | 201 | * 0xff means "always match" |
201 | */ | 202 | */ |
202 | mday = tm->tm_mday; | 203 | mday = tm->tm_mday; |
203 | mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff; | 204 | mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff; |
204 | if (mday == 0xff) | 205 | if (mday == 0xff) |
205 | mday = M48T59_READ(M48T59_MDAY); | 206 | mday = M48T59_READ(M48T59_MDAY); |
206 | 207 | ||
207 | hour = tm->tm_hour; | 208 | hour = tm->tm_hour; |
208 | hour = (hour < 24) ? BIN2BCD(hour) : 0x00; | 209 | hour = (hour < 24) ? bin2bcd(hour) : 0x00; |
209 | 210 | ||
210 | min = tm->tm_min; | 211 | min = tm->tm_min; |
211 | min = (min < 60) ? BIN2BCD(min) : 0x00; | 212 | min = (min < 60) ? bin2bcd(min) : 0x00; |
212 | 213 | ||
213 | sec = tm->tm_sec; | 214 | sec = tm->tm_sec; |
214 | sec = (sec < 60) ? BIN2BCD(sec) : 0x00; | 215 | sec = (sec < 60) ? bin2bcd(sec) : 0x00; |
215 | 216 | ||
216 | spin_lock_irqsave(&m48t59->lock, flags); | 217 | spin_lock_irqsave(&m48t59->lock, flags); |
217 | /* Issue the WRITE command */ | 218 | /* Issue the WRITE command */ |
@@ -310,6 +311,11 @@ static const struct rtc_class_ops m48t59_rtc_ops = { | |||
310 | .proc = m48t59_rtc_proc, | 311 | .proc = m48t59_rtc_proc, |
311 | }; | 312 | }; |
312 | 313 | ||
314 | static const struct rtc_class_ops m48t02_rtc_ops = { | ||
315 | .read_time = m48t59_rtc_read_time, | ||
316 | .set_time = m48t59_rtc_set_time, | ||
317 | }; | ||
318 | |||
313 | static ssize_t m48t59_nvram_read(struct kobject *kobj, | 319 | static ssize_t m48t59_nvram_read(struct kobject *kobj, |
314 | struct bin_attribute *bin_attr, | 320 | struct bin_attribute *bin_attr, |
315 | char *buf, loff_t pos, size_t size) | 321 | char *buf, loff_t pos, size_t size) |
@@ -321,7 +327,7 @@ static ssize_t m48t59_nvram_read(struct kobject *kobj, | |||
321 | ssize_t cnt = 0; | 327 | ssize_t cnt = 0; |
322 | unsigned long flags; | 328 | unsigned long flags; |
323 | 329 | ||
324 | for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { | 330 | for (; size > 0 && pos < pdata->offset; cnt++, size--) { |
325 | spin_lock_irqsave(&m48t59->lock, flags); | 331 | spin_lock_irqsave(&m48t59->lock, flags); |
326 | *buf++ = M48T59_READ(cnt); | 332 | *buf++ = M48T59_READ(cnt); |
327 | spin_unlock_irqrestore(&m48t59->lock, flags); | 333 | spin_unlock_irqrestore(&m48t59->lock, flags); |
@@ -341,7 +347,7 @@ static ssize_t m48t59_nvram_write(struct kobject *kobj, | |||
341 | ssize_t cnt = 0; | 347 | ssize_t cnt = 0; |
342 | unsigned long flags; | 348 | unsigned long flags; |
343 | 349 | ||
344 | for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { | 350 | for (; size > 0 && pos < pdata->offset; cnt++, size--) { |
345 | spin_lock_irqsave(&m48t59->lock, flags); | 351 | spin_lock_irqsave(&m48t59->lock, flags); |
346 | M48T59_WRITE(*buf++, cnt); | 352 | M48T59_WRITE(*buf++, cnt); |
347 | spin_unlock_irqrestore(&m48t59->lock, flags); | 353 | spin_unlock_irqrestore(&m48t59->lock, flags); |
@@ -354,11 +360,9 @@ static struct bin_attribute m48t59_nvram_attr = { | |||
354 | .attr = { | 360 | .attr = { |
355 | .name = "nvram", | 361 | .name = "nvram", |
356 | .mode = S_IRUGO | S_IWUSR, | 362 | .mode = S_IRUGO | S_IWUSR, |
357 | .owner = THIS_MODULE, | ||
358 | }, | 363 | }, |
359 | .read = m48t59_nvram_read, | 364 | .read = m48t59_nvram_read, |
360 | .write = m48t59_nvram_write, | 365 | .write = m48t59_nvram_write, |
361 | .size = M48T59_NVRAM_SIZE, | ||
362 | }; | 366 | }; |
363 | 367 | ||
364 | static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | 368 | static int __devinit m48t59_rtc_probe(struct platform_device *pdev) |
@@ -367,6 +371,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
367 | struct m48t59_private *m48t59 = NULL; | 371 | struct m48t59_private *m48t59 = NULL; |
368 | struct resource *res; | 372 | struct resource *res; |
369 | int ret = -ENOMEM; | 373 | int ret = -ENOMEM; |
374 | char *name; | ||
375 | const struct rtc_class_ops *ops; | ||
370 | 376 | ||
371 | /* This chip could be memory-mapped or I/O-mapped */ | 377 | /* This chip could be memory-mapped or I/O-mapped */ |
372 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 378 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -391,6 +397,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
391 | /* Ensure we only kmalloc platform data once */ | 397 | /* Ensure we only kmalloc platform data once */ |
392 | pdev->dev.platform_data = pdata; | 398 | pdev->dev.platform_data = pdata; |
393 | } | 399 | } |
400 | if (!pdata->type) | ||
401 | pdata->type = M48T59RTC_TYPE_M48T59; | ||
394 | 402 | ||
395 | /* Try to use the generic memory read/write ops */ | 403 | /* Try to use the generic memory read/write ops */ |
396 | if (!pdata->write_byte) | 404 | if (!pdata->write_byte) |
@@ -403,10 +411,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
403 | if (!m48t59) | 411 | if (!m48t59) |
404 | return -ENOMEM; | 412 | return -ENOMEM; |
405 | 413 | ||
406 | m48t59->size = res->end - res->start + 1; | 414 | m48t59->ioaddr = pdata->ioaddr; |
407 | m48t59->ioaddr = ioremap(res->start, m48t59->size); | 415 | |
408 | if (!m48t59->ioaddr) | 416 | if (!m48t59->ioaddr) { |
409 | goto out; | 417 | /* ioaddr not mapped externally */ |
418 | m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1); | ||
419 | if (!m48t59->ioaddr) | ||
420 | goto out; | ||
421 | } | ||
410 | 422 | ||
411 | /* Try to get irq number. We also can work in | 423 | /* Try to get irq number. We also can work in |
412 | * the mode without IRQ. | 424 | * the mode without IRQ. |
@@ -421,14 +433,36 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
421 | if (ret) | 433 | if (ret) |
422 | goto out; | 434 | goto out; |
423 | } | 435 | } |
436 | switch (pdata->type) { | ||
437 | case M48T59RTC_TYPE_M48T59: | ||
438 | name = "m48t59"; | ||
439 | ops = &m48t59_rtc_ops; | ||
440 | pdata->offset = 0x1ff0; | ||
441 | break; | ||
442 | case M48T59RTC_TYPE_M48T02: | ||
443 | name = "m48t02"; | ||
444 | ops = &m48t02_rtc_ops; | ||
445 | pdata->offset = 0x7f0; | ||
446 | break; | ||
447 | case M48T59RTC_TYPE_M48T08: | ||
448 | name = "m48t08"; | ||
449 | ops = &m48t02_rtc_ops; | ||
450 | pdata->offset = 0x1ff0; | ||
451 | break; | ||
452 | default: | ||
453 | dev_err(&pdev->dev, "Unknown RTC type\n"); | ||
454 | ret = -ENODEV; | ||
455 | goto out; | ||
456 | } | ||
424 | 457 | ||
425 | m48t59->rtc = rtc_device_register("m48t59", &pdev->dev, | 458 | m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE); |
426 | &m48t59_rtc_ops, THIS_MODULE); | ||
427 | if (IS_ERR(m48t59->rtc)) { | 459 | if (IS_ERR(m48t59->rtc)) { |
428 | ret = PTR_ERR(m48t59->rtc); | 460 | ret = PTR_ERR(m48t59->rtc); |
429 | goto out; | 461 | goto out; |
430 | } | 462 | } |
431 | 463 | ||
464 | m48t59_nvram_attr.size = pdata->offset; | ||
465 | |||
432 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); | 466 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); |
433 | if (ret) | 467 | if (ret) |
434 | goto out; | 468 | goto out; |
@@ -452,11 +486,12 @@ out: | |||
452 | static int __devexit m48t59_rtc_remove(struct platform_device *pdev) | 486 | static int __devexit m48t59_rtc_remove(struct platform_device *pdev) |
453 | { | 487 | { |
454 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | 488 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); |
489 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
455 | 490 | ||
456 | sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); | 491 | sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); |
457 | if (!IS_ERR(m48t59->rtc)) | 492 | if (!IS_ERR(m48t59->rtc)) |
458 | rtc_device_unregister(m48t59->rtc); | 493 | rtc_device_unregister(m48t59->rtc); |
459 | if (m48t59->ioaddr) | 494 | if (m48t59->ioaddr && !pdata->ioaddr) |
460 | iounmap(m48t59->ioaddr); | 495 | iounmap(m48t59->ioaddr); |
461 | if (m48t59->irq != NO_IRQ) | 496 | if (m48t59->irq != NO_IRQ) |
462 | free_irq(m48t59->irq, &pdev->dev); | 497 | free_irq(m48t59->irq, &pdev->dev); |
@@ -491,5 +526,5 @@ module_init(m48t59_rtc_init); | |||
491 | module_exit(m48t59_rtc_exit); | 526 | module_exit(m48t59_rtc_exit); |
492 | 527 | ||
493 | MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>"); | 528 | MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>"); |
494 | MODULE_DESCRIPTION("M48T59 RTC driver"); | 529 | MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver"); |
495 | MODULE_LICENSE("GPL"); | 530 | MODULE_LICENSE("GPL"); |