diff options
Diffstat (limited to 'drivers/rtc/rtc-m48t59.c')
-rw-r--r-- | drivers/rtc/rtc-m48t59.c | 68 |
1 files changed, 52 insertions, 16 deletions
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 013e6c103b9c..ce4eff6a8d51 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 */ |
@@ -82,7 +82,8 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
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 | } |
@@ -126,7 +127,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
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); |
@@ -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); |
@@ -358,7 +364,6 @@ static struct bin_attribute m48t59_nvram_attr = { | |||
358 | }, | 364 | }, |
359 | .read = m48t59_nvram_read, | 365 | .read = m48t59_nvram_read, |
360 | .write = m48t59_nvram_write, | 366 | .write = m48t59_nvram_write, |
361 | .size = M48T59_NVRAM_SIZE, | ||
362 | }; | 367 | }; |
363 | 368 | ||
364 | static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | 369 | static int __devinit m48t59_rtc_probe(struct platform_device *pdev) |
@@ -367,6 +372,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
367 | struct m48t59_private *m48t59 = NULL; | 372 | struct m48t59_private *m48t59 = NULL; |
368 | struct resource *res; | 373 | struct resource *res; |
369 | int ret = -ENOMEM; | 374 | int ret = -ENOMEM; |
375 | char *name; | ||
376 | const struct rtc_class_ops *ops; | ||
370 | 377 | ||
371 | /* This chip could be memory-mapped or I/O-mapped */ | 378 | /* This chip could be memory-mapped or I/O-mapped */ |
372 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 379 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -391,6 +398,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
391 | /* Ensure we only kmalloc platform data once */ | 398 | /* Ensure we only kmalloc platform data once */ |
392 | pdev->dev.platform_data = pdata; | 399 | pdev->dev.platform_data = pdata; |
393 | } | 400 | } |
401 | if (!pdata->type) | ||
402 | pdata->type = M48T59RTC_TYPE_M48T59; | ||
394 | 403 | ||
395 | /* Try to use the generic memory read/write ops */ | 404 | /* Try to use the generic memory read/write ops */ |
396 | if (!pdata->write_byte) | 405 | if (!pdata->write_byte) |
@@ -403,10 +412,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
403 | if (!m48t59) | 412 | if (!m48t59) |
404 | return -ENOMEM; | 413 | return -ENOMEM; |
405 | 414 | ||
406 | m48t59->size = res->end - res->start + 1; | 415 | m48t59->ioaddr = pdata->ioaddr; |
407 | m48t59->ioaddr = ioremap(res->start, m48t59->size); | 416 | |
408 | if (!m48t59->ioaddr) | 417 | if (!m48t59->ioaddr) { |
409 | goto out; | 418 | /* ioaddr not mapped externally */ |
419 | m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1); | ||
420 | if (!m48t59->ioaddr) | ||
421 | goto out; | ||
422 | } | ||
410 | 423 | ||
411 | /* Try to get irq number. We also can work in | 424 | /* Try to get irq number. We also can work in |
412 | * the mode without IRQ. | 425 | * the mode without IRQ. |
@@ -421,14 +434,36 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | |||
421 | if (ret) | 434 | if (ret) |
422 | goto out; | 435 | goto out; |
423 | } | 436 | } |
437 | switch (pdata->type) { | ||
438 | case M48T59RTC_TYPE_M48T59: | ||
439 | name = "m48t59"; | ||
440 | ops = &m48t59_rtc_ops; | ||
441 | pdata->offset = 0x1ff0; | ||
442 | break; | ||
443 | case M48T59RTC_TYPE_M48T02: | ||
444 | name = "m48t02"; | ||
445 | ops = &m48t02_rtc_ops; | ||
446 | pdata->offset = 0x7f0; | ||
447 | break; | ||
448 | case M48T59RTC_TYPE_M48T08: | ||
449 | name = "m48t08"; | ||
450 | ops = &m48t02_rtc_ops; | ||
451 | pdata->offset = 0x1ff0; | ||
452 | break; | ||
453 | default: | ||
454 | dev_err(&pdev->dev, "Unknown RTC type\n"); | ||
455 | ret = -ENODEV; | ||
456 | goto out; | ||
457 | } | ||
424 | 458 | ||
425 | m48t59->rtc = rtc_device_register("m48t59", &pdev->dev, | 459 | m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE); |
426 | &m48t59_rtc_ops, THIS_MODULE); | ||
427 | if (IS_ERR(m48t59->rtc)) { | 460 | if (IS_ERR(m48t59->rtc)) { |
428 | ret = PTR_ERR(m48t59->rtc); | 461 | ret = PTR_ERR(m48t59->rtc); |
429 | goto out; | 462 | goto out; |
430 | } | 463 | } |
431 | 464 | ||
465 | m48t59_nvram_attr.size = pdata->offset; | ||
466 | |||
432 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); | 467 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); |
433 | if (ret) | 468 | if (ret) |
434 | goto out; | 469 | goto out; |
@@ -452,11 +487,12 @@ out: | |||
452 | static int __devexit m48t59_rtc_remove(struct platform_device *pdev) | 487 | static int __devexit m48t59_rtc_remove(struct platform_device *pdev) |
453 | { | 488 | { |
454 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | 489 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); |
490 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
455 | 491 | ||
456 | sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); | 492 | sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); |
457 | if (!IS_ERR(m48t59->rtc)) | 493 | if (!IS_ERR(m48t59->rtc)) |
458 | rtc_device_unregister(m48t59->rtc); | 494 | rtc_device_unregister(m48t59->rtc); |
459 | if (m48t59->ioaddr) | 495 | if (m48t59->ioaddr && !pdata->ioaddr) |
460 | iounmap(m48t59->ioaddr); | 496 | iounmap(m48t59->ioaddr); |
461 | if (m48t59->irq != NO_IRQ) | 497 | if (m48t59->irq != NO_IRQ) |
462 | free_irq(m48t59->irq, &pdev->dev); | 498 | free_irq(m48t59->irq, &pdev->dev); |
@@ -491,5 +527,5 @@ module_init(m48t59_rtc_init); | |||
491 | module_exit(m48t59_rtc_exit); | 527 | module_exit(m48t59_rtc_exit); |
492 | 528 | ||
493 | MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>"); | 529 | MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>"); |
494 | MODULE_DESCRIPTION("M48T59 RTC driver"); | 530 | MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver"); |
495 | MODULE_LICENSE("GPL"); | 531 | MODULE_LICENSE("GPL"); |