ds1374.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * drivers/i2c/chips/ds1374.c
  3. *
  4. * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock
  5. *
  6. * Author: Randy Vinson <rvinson@mvista.com>
  7. *
  8. * Based on the m41t00.c by Mark Greer <mgreer@mvista.com>
  9. *
  10. * 2005 (c) MontaVista Software, Inc. This file is licensed under
  11. * the terms of the GNU General Public License version 2. This program
  12. * is licensed "as is" without any warranty of any kind, whether express
  13. * or implied.
  14. */
  15. /*
  16. * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
  17. * interface and the SMBus interface of the i2c subsystem.
  18. * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
  19. * recommened in .../Documentation/i2c/writing-clients section
  20. * "Sending and receiving", using SMBus level communication is preferred.
  21. */
  22. #include <linux/kernel.h>
  23. #include <linux/module.h>
  24. #include <linux/interrupt.h>
  25. #include <linux/i2c.h>
  26. #include <linux/rtc.h>
  27. #include <linux/bcd.h>
  28. #define DS1374_REG_TOD0 0x00
  29. #define DS1374_REG_TOD1 0x01
  30. #define DS1374_REG_TOD2 0x02
  31. #define DS1374_REG_TOD3 0x03
  32. #define DS1374_REG_WDALM0 0x04
  33. #define DS1374_REG_WDALM1 0x05
  34. #define DS1374_REG_WDALM2 0x06
  35. #define DS1374_REG_CR 0x07
  36. #define DS1374_REG_SR 0x08
  37. #define DS1374_REG_SR_OSF 0x80
  38. #define DS1374_REG_TCR 0x09
  39. #define DS1374_DRV_NAME "ds1374"
  40. static DECLARE_MUTEX(ds1374_mutex);
  41. static struct i2c_driver ds1374_driver;
  42. static struct i2c_client *save_client;
  43. static unsigned short ignore[] = { I2C_CLIENT_END };
  44. static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
  45. static struct i2c_client_address_data addr_data = {
  46. .normal_i2c = normal_addr,
  47. .probe = ignore,
  48. .ignore = ignore,
  49. };
  50. static ulong ds1374_read_rtc(void)
  51. {
  52. ulong time = 0;
  53. int reg = DS1374_REG_WDALM0;
  54. while (reg--) {
  55. s32 tmp;
  56. if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
  57. dev_warn(&save_client->dev,
  58. "can't read from rtc chip\n");
  59. return 0;
  60. }
  61. time = (time << 8) | (tmp & 0xff);
  62. }
  63. return time;
  64. }
  65. static void ds1374_write_rtc(ulong time)
  66. {
  67. int reg;
  68. for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
  69. if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
  70. < 0) {
  71. dev_warn(&save_client->dev,
  72. "can't write to rtc chip\n");
  73. break;
  74. }
  75. time = time >> 8;
  76. }
  77. }
  78. static void ds1374_check_rtc_status(void)
  79. {
  80. s32 tmp;
  81. tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
  82. if (tmp < 0) {
  83. dev_warn(&save_client->dev,
  84. "can't read status from rtc chip\n");
  85. return;
  86. }
  87. if (tmp & DS1374_REG_SR_OSF) {
  88. dev_warn(&save_client->dev,
  89. "oscillator discontinuity flagged, time unreliable\n");
  90. tmp &= ~DS1374_REG_SR_OSF;
  91. tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
  92. tmp & 0xff);
  93. if (tmp < 0)
  94. dev_warn(&save_client->dev,
  95. "can't clear discontinuity notification\n");
  96. }
  97. }
  98. ulong ds1374_get_rtc_time(void)
  99. {
  100. ulong t1, t2;
  101. int limit = 10; /* arbitrary retry limit */
  102. down(&ds1374_mutex);
  103. /*
  104. * Since the reads are being performed one byte at a time using
  105. * the SMBus vs a 4-byte i2c transfer, there is a chance that a
  106. * carry will occur during the read. To detect this, 2 reads are
  107. * performed and compared.
  108. */
  109. do {
  110. t1 = ds1374_read_rtc();
  111. t2 = ds1374_read_rtc();
  112. } while (t1 != t2 && limit--);
  113. up(&ds1374_mutex);
  114. if (t1 != t2) {
  115. dev_warn(&save_client->dev,
  116. "can't get consistent time from rtc chip\n");
  117. t1 = 0;
  118. }
  119. return t1;
  120. }
  121. static void ds1374_set_tlet(ulong arg)
  122. {
  123. ulong t1, t2;
  124. int limit = 10; /* arbitrary retry limit */
  125. t1 = *(ulong *) arg;
  126. down(&ds1374_mutex);
  127. /*
  128. * Since the writes are being performed one byte at a time using
  129. * the SMBus vs a 4-byte i2c transfer, there is a chance that a
  130. * carry will occur during the write. To detect this, the write
  131. * value is read back and compared.
  132. */
  133. do {
  134. ds1374_write_rtc(t1);
  135. t2 = ds1374_read_rtc();
  136. } while (t1 != t2 && limit--);
  137. up(&ds1374_mutex);
  138. if (t1 != t2)
  139. dev_warn(&save_client->dev,
  140. "can't confirm time set from rtc chip\n");
  141. }
  142. static ulong new_time;
  143. static DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet,
  144. (ulong) & new_time);
  145. int ds1374_set_rtc_time(ulong nowtime)
  146. {
  147. new_time = nowtime;
  148. if (in_interrupt())
  149. tasklet_schedule(&ds1374_tasklet);
  150. else
  151. ds1374_set_tlet((ulong) & new_time);
  152. return 0;
  153. }
  154. /*
  155. *****************************************************************************
  156. *
  157. * Driver Interface
  158. *
  159. *****************************************************************************
  160. */
  161. static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
  162. {
  163. struct i2c_client *client;
  164. int rc;
  165. client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
  166. if (!client)
  167. return -ENOMEM;
  168. strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
  169. client->addr = addr;
  170. client->adapter = adap;
  171. client->driver = &ds1374_driver;
  172. if ((rc = i2c_attach_client(client)) != 0) {
  173. kfree(client);
  174. return rc;
  175. }
  176. save_client = client;
  177. ds1374_check_rtc_status();
  178. return 0;
  179. }
  180. static int ds1374_attach(struct i2c_adapter *adap)
  181. {
  182. return i2c_probe(adap, &addr_data, ds1374_probe);
  183. }
  184. static int ds1374_detach(struct i2c_client *client)
  185. {
  186. int rc;
  187. if ((rc = i2c_detach_client(client)) == 0) {
  188. kfree(i2c_get_clientdata(client));
  189. tasklet_kill(&ds1374_tasklet);
  190. }
  191. return rc;
  192. }
  193. static struct i2c_driver ds1374_driver = {
  194. .driver = {
  195. .name = DS1374_DRV_NAME,
  196. },
  197. .id = I2C_DRIVERID_DS1374,
  198. .attach_adapter = ds1374_attach,
  199. .detach_client = ds1374_detach,
  200. };
  201. static int __init ds1374_init(void)
  202. {
  203. return i2c_add_driver(&ds1374_driver);
  204. }
  205. static void __exit ds1374_exit(void)
  206. {
  207. i2c_del_driver(&ds1374_driver);
  208. }
  209. module_init(ds1374_init);
  210. module_exit(ds1374_exit);
  211. MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>");
  212. MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
  213. MODULE_LICENSE("GPL");