rtc-bq4802.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /* rtc-bq4802.c: TI BQ4802 RTC driver.
  2. *
  3. * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  4. */
  5. #include <linux/kernel.h>
  6. #include <linux/module.h>
  7. #include <linux/init.h>
  8. #include <linux/io.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/rtc.h>
  11. #include <linux/bcd.h>
  12. MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
  13. MODULE_DESCRIPTION("TI BQ4802 RTC driver");
  14. MODULE_LICENSE("GPL");
  15. struct bq4802 {
  16. void __iomem *regs;
  17. struct rtc_device *rtc;
  18. spinlock_t lock;
  19. struct resource *r;
  20. u8 (*read)(struct bq4802 *, int);
  21. void (*write)(struct bq4802 *, int, u8);
  22. };
  23. static u8 bq4802_read_io(struct bq4802 *p, int off)
  24. {
  25. return inb(p->regs + off);
  26. }
  27. static void bq4802_write_io(struct bq4802 *p, int off, u8 val)
  28. {
  29. return outb(val, p->regs + off);
  30. }
  31. static u8 bq4802_read_mem(struct bq4802 *p, int off)
  32. {
  33. return readb(p->regs + off);
  34. }
  35. static void bq4802_write_mem(struct bq4802 *p, int off, u8 val)
  36. {
  37. return writeb(val, p->regs + off);
  38. }
  39. static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
  40. {
  41. struct platform_device *pdev = to_platform_device(dev);
  42. struct bq4802 *p = platform_get_drvdata(pdev);
  43. unsigned long flags;
  44. unsigned int century;
  45. u8 val;
  46. spin_lock_irqsave(&p->lock, flags);
  47. val = p->read(p, 0x0e);
  48. p->write(p, 0xe, val | 0x08);
  49. tm->tm_sec = p->read(p, 0x00);
  50. tm->tm_min = p->read(p, 0x02);
  51. tm->tm_hour = p->read(p, 0x04);
  52. tm->tm_mday = p->read(p, 0x06);
  53. tm->tm_mon = p->read(p, 0x09);
  54. tm->tm_year = p->read(p, 0x0a);
  55. tm->tm_wday = p->read(p, 0x08);
  56. century = p->read(p, 0x0f);
  57. p->write(p, 0x0e, val);
  58. spin_unlock_irqrestore(&p->lock, flags);
  59. BCD_TO_BIN(tm->tm_sec);
  60. BCD_TO_BIN(tm->tm_min);
  61. BCD_TO_BIN(tm->tm_hour);
  62. BCD_TO_BIN(tm->tm_mday);
  63. BCD_TO_BIN(tm->tm_mon);
  64. BCD_TO_BIN(tm->tm_year);
  65. BCD_TO_BIN(tm->tm_wday);
  66. BCD_TO_BIN(century);
  67. tm->tm_year += (century * 100);
  68. tm->tm_year -= 1900;
  69. tm->tm_mon--;
  70. return 0;
  71. }
  72. static int bq4802_set_time(struct device *dev, struct rtc_time *tm)
  73. {
  74. struct platform_device *pdev = to_platform_device(dev);
  75. struct bq4802 *p = platform_get_drvdata(pdev);
  76. u8 sec, min, hrs, day, mon, yrs, century, val;
  77. unsigned long flags;
  78. unsigned int year;
  79. year = tm->tm_year + 1900;
  80. century = year / 100;
  81. yrs = year % 100;
  82. mon = tm->tm_mon + 1; /* tm_mon starts at zero */
  83. day = tm->tm_mday;
  84. hrs = tm->tm_hour;
  85. min = tm->tm_min;
  86. sec = tm->tm_sec;
  87. BIN_TO_BCD(sec);
  88. BIN_TO_BCD(min);
  89. BIN_TO_BCD(hrs);
  90. BIN_TO_BCD(day);
  91. BIN_TO_BCD(mon);
  92. BIN_TO_BCD(yrs);
  93. BIN_TO_BCD(century);
  94. spin_lock_irqsave(&p->lock, flags);
  95. val = p->read(p, 0x0e);
  96. p->write(p, 0x0e, val | 0x08);
  97. p->write(p, 0x00, sec);
  98. p->write(p, 0x02, min);
  99. p->write(p, 0x04, hrs);
  100. p->write(p, 0x06, day);
  101. p->write(p, 0x09, mon);
  102. p->write(p, 0x0a, yrs);
  103. p->write(p, 0x0f, century);
  104. p->write(p, 0x0e, val);
  105. spin_unlock_irqrestore(&p->lock, flags);
  106. return 0;
  107. }
  108. static const struct rtc_class_ops bq4802_ops = {
  109. .read_time = bq4802_read_time,
  110. .set_time = bq4802_set_time,
  111. };
  112. static int __devinit bq4802_probe(struct platform_device *pdev)
  113. {
  114. struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
  115. int err = -ENOMEM;
  116. if (!p)
  117. goto out;
  118. spin_lock_init(&p->lock);
  119. p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  120. if (!p->r) {
  121. p->r = platform_get_resource(pdev, IORESOURCE_IO, 0);
  122. err = -EINVAL;
  123. if (!p->r)
  124. goto out_free;
  125. }
  126. if (p->r->flags & IORESOURCE_IO) {
  127. p->regs = (void __iomem *) p->r->start;
  128. p->read = bq4802_read_io;
  129. p->write = bq4802_write_io;
  130. } else if (p->r->flags & IORESOURCE_MEM) {
  131. p->regs = ioremap(p->r->start, resource_size(p->r));
  132. p->read = bq4802_read_mem;
  133. p->write = bq4802_write_mem;
  134. } else {
  135. err = -EINVAL;
  136. goto out_free;
  137. }
  138. p->rtc = rtc_device_register("bq4802", &pdev->dev,
  139. &bq4802_ops, THIS_MODULE);
  140. if (IS_ERR(p->rtc)) {
  141. err = PTR_ERR(p->rtc);
  142. goto out_iounmap;
  143. }
  144. platform_set_drvdata(pdev, p);
  145. err = 0;
  146. out:
  147. return err;
  148. out_iounmap:
  149. if (p->r->flags & IORESOURCE_MEM)
  150. iounmap(p->regs);
  151. out_free:
  152. kfree(p);
  153. goto out;
  154. }
  155. static int __devexit bq4802_remove(struct platform_device *pdev)
  156. {
  157. struct bq4802 *p = platform_get_drvdata(pdev);
  158. rtc_device_unregister(p->rtc);
  159. if (p->r->flags & IORESOURCE_MEM)
  160. iounmap(p->regs);
  161. platform_set_drvdata(pdev, NULL);
  162. kfree(p);
  163. return 0;
  164. }
  165. /* work with hotplug and coldplug */
  166. MODULE_ALIAS("platform:rtc-bq4802");
  167. static struct platform_driver bq4802_driver = {
  168. .driver = {
  169. .name = "rtc-bq4802",
  170. .owner = THIS_MODULE,
  171. },
  172. .probe = bq4802_probe,
  173. .remove = __devexit_p(bq4802_remove),
  174. };
  175. static int __init bq4802_init(void)
  176. {
  177. return platform_driver_register(&bq4802_driver);
  178. }
  179. static void __exit bq4802_exit(void)
  180. {
  181. platform_driver_unregister(&bq4802_driver);
  182. }
  183. module_init(bq4802_init);
  184. module_exit(bq4802_exit);