Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc-m48t59: add support for M48T02 and M48T59 chips

Add support for two compatible RTC:
- M48T08 which does not have alarm part,
- M48T08 which does not have alarm part and has
only 2KB of NVRAM

These types covers all Mostek's RTC used in Sun UltraSparc workstations.

Tested on Sun Ultra60 with M48T59 RTC.

Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Krzysztof Helt and committed by
David S. Miller
94fe7424 3ca60f6e

+69 -30
+5 -2
drivers/rtc/Kconfig
··· 406 406 will be called rtc-m48t86. 407 407 408 408 config RTC_DRV_M48T59 409 - tristate "ST M48T59" 409 + tristate "ST M48T59/M48T08/M48T02" 410 410 help 411 411 If you say Y here you will get support for the 412 - ST M48T59 RTC chip. 412 + ST M48T59 RTC chip and compatible ST M48T08 and M48T02. 413 + 414 + These chips are usually found in Sun SPARC and UltraSPARC 415 + workstations. 413 416 414 417 This driver can also be built as a module, if so, the module 415 418 will be called "rtc-m48t59".
+39 -8
drivers/rtc/rtc-m48t59.c
··· 24 24 #define NO_IRQ (-1) 25 25 #endif 26 26 27 - #define M48T59_READ(reg) pdata->read_byte(dev, reg) 28 - #define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val) 27 + #define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg)) 28 + #define M48T59_WRITE(val, reg) \ 29 + (pdata->write_byte(dev, pdata->offset + reg, val)) 29 30 30 31 #define M48T59_SET_BITS(mask, reg) \ 31 32 M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg)) ··· 310 309 .proc = m48t59_rtc_proc, 311 310 }; 312 311 312 + static const struct rtc_class_ops m48t02_rtc_ops = { 313 + .read_time = m48t59_rtc_read_time, 314 + .set_time = m48t59_rtc_set_time, 315 + }; 316 + 313 317 static ssize_t m48t59_nvram_read(struct kobject *kobj, 314 318 struct bin_attribute *bin_attr, 315 319 char *buf, loff_t pos, size_t size) ··· 326 320 ssize_t cnt = 0; 327 321 unsigned long flags; 328 322 329 - for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { 323 + for (; size > 0 && pos < pdata->offset; cnt++, size--) { 330 324 spin_lock_irqsave(&m48t59->lock, flags); 331 325 *buf++ = M48T59_READ(cnt); 332 326 spin_unlock_irqrestore(&m48t59->lock, flags); ··· 346 340 ssize_t cnt = 0; 347 341 unsigned long flags; 348 342 349 - for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { 343 + for (; size > 0 && pos < pdata->offset; cnt++, size--) { 350 344 spin_lock_irqsave(&m48t59->lock, flags); 351 345 M48T59_WRITE(*buf++, cnt); 352 346 spin_unlock_irqrestore(&m48t59->lock, flags); ··· 363 357 }, 364 358 .read = m48t59_nvram_read, 365 359 .write = m48t59_nvram_write, 366 - .size = M48T59_NVRAM_SIZE, 367 360 }; 368 361 369 362 static int __devinit m48t59_rtc_probe(struct platform_device *pdev) ··· 371 366 struct m48t59_private *m48t59 = NULL; 372 367 struct resource *res; 373 368 int ret = -ENOMEM; 369 + char *name; 370 + const struct rtc_class_ops *ops; 374 371 375 372 /* This chip could be memory-mapped or I/O-mapped */ 376 373 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ··· 397 390 /* Ensure we only kmalloc platform data once */ 398 391 pdev->dev.platform_data = pdata; 399 392 } 393 + if (!pdata->type) 394 + pdata->type = M48T59RTC_TYPE_M48T59; 400 395 401 396 /* Try to use the generic memory read/write ops */ 402 397 if (!pdata->write_byte) ··· 428 419 if (ret) 429 420 goto out; 430 421 } 422 + switch (pdata->type) { 423 + case M48T59RTC_TYPE_M48T59: 424 + name = "m48t59"; 425 + ops = &m48t59_rtc_ops; 426 + pdata->offset = 0x1ff0; 427 + break; 428 + case M48T59RTC_TYPE_M48T02: 429 + name = "m48t02"; 430 + ops = &m48t02_rtc_ops; 431 + pdata->offset = 0x7f0; 432 + break; 433 + case M48T59RTC_TYPE_M48T08: 434 + name = "m48t08"; 435 + ops = &m48t02_rtc_ops; 436 + pdata->offset = 0x1ff0; 437 + break; 438 + default: 439 + dev_err(&pdev->dev, "Unknown RTC type\n"); 440 + ret = -ENODEV; 441 + goto out; 442 + } 431 443 432 - m48t59->rtc = rtc_device_register("m48t59", &pdev->dev, 433 - &m48t59_rtc_ops, THIS_MODULE); 444 + m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE); 434 445 if (IS_ERR(m48t59->rtc)) { 435 446 ret = PTR_ERR(m48t59->rtc); 436 447 goto out; 437 448 } 449 + 450 + m48t59_nvram_attr.size = pdata->offset; 438 451 439 452 ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); 440 453 if (ret) ··· 520 489 module_exit(m48t59_rtc_exit); 521 490 522 491 MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>"); 523 - MODULE_DESCRIPTION("M48T59 RTC driver"); 492 + MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver"); 524 493 MODULE_LICENSE("GPL");
+25 -20
include/linux/rtc/m48t59.h
··· 18 18 /* 19 19 * M48T59 Register Offset 20 20 */ 21 - #define M48T59_YEAR 0x1fff 22 - #define M48T59_MONTH 0x1ffe 23 - #define M48T59_MDAY 0x1ffd /* Day of Month */ 24 - #define M48T59_WDAY 0x1ffc /* Day of Week */ 21 + #define M48T59_YEAR 0xf 22 + #define M48T59_MONTH 0xe 23 + #define M48T59_MDAY 0xd /* Day of Month */ 24 + #define M48T59_WDAY 0xc /* Day of Week */ 25 25 #define M48T59_WDAY_CB 0x20 /* Century Bit */ 26 26 #define M48T59_WDAY_CEB 0x10 /* Century Enable Bit */ 27 - #define M48T59_HOUR 0x1ffb 28 - #define M48T59_MIN 0x1ffa 29 - #define M48T59_SEC 0x1ff9 30 - #define M48T59_CNTL 0x1ff8 27 + #define M48T59_HOUR 0xb 28 + #define M48T59_MIN 0xa 29 + #define M48T59_SEC 0x9 30 + #define M48T59_CNTL 0x8 31 31 #define M48T59_CNTL_READ 0x40 32 32 #define M48T59_CNTL_WRITE 0x80 33 - #define M48T59_WATCHDOG 0x1ff7 34 - #define M48T59_INTR 0x1ff6 33 + #define M48T59_WATCHDOG 0x7 34 + #define M48T59_INTR 0x6 35 35 #define M48T59_INTR_AFE 0x80 /* Alarm Interrupt Enable */ 36 36 #define M48T59_INTR_ABE 0x20 37 - #define M48T59_ALARM_DATE 0x1ff5 38 - #define M48T59_ALARM_HOUR 0x1ff4 39 - #define M48T59_ALARM_MIN 0x1ff3 40 - #define M48T59_ALARM_SEC 0x1ff2 41 - #define M48T59_UNUSED 0x1ff1 42 - #define M48T59_FLAGS 0x1ff0 37 + #define M48T59_ALARM_DATE 0x5 38 + #define M48T59_ALARM_HOUR 0x4 39 + #define M48T59_ALARM_MIN 0x3 40 + #define M48T59_ALARM_SEC 0x2 41 + #define M48T59_UNUSED 0x1 42 + #define M48T59_FLAGS 0x0 43 43 #define M48T59_FLAGS_WDT 0x80 /* watchdog timer expired */ 44 44 #define M48T59_FLAGS_AF 0x40 /* alarm */ 45 45 #define M48T59_FLAGS_BF 0x10 /* low battery */ 46 46 47 - #define M48T59_NVRAM_SIZE 0x1ff0 47 + #define M48T59RTC_TYPE_M48T59 0 /* to keep compatibility */ 48 + #define M48T59RTC_TYPE_M48T02 1 49 + #define M48T59RTC_TYPE_M48T08 2 48 50 49 51 struct m48t59_plat_data { 50 - /* The method to access M48T59 registers, 51 - * NOTE: The 'ofs' should be 0x00~0x1fff 52 - */ 52 + /* The method to access M48T59 registers */ 53 53 void (*write_byte)(struct device *dev, u32 ofs, u8 val); 54 54 unsigned char (*read_byte)(struct device *dev, u32 ofs); 55 + 56 + int type; /* RTC model */ 57 + 58 + /* offset to RTC registers, automatically set according to the type */ 59 + unsigned int offset; 55 60 }; 56 61 57 62 #endif /* _LINUX_RTC_M48T59_H_ */