ds1374.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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. .force = ignore,
  50. };
  51. static ulong ds1374_read_rtc(void)
  52. {
  53. ulong time = 0;
  54. int reg = DS1374_REG_WDALM0;
  55. while (reg--) {
  56. s32 tmp;
  57. if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
  58. dev_warn(&save_client->dev,
  59. "can't read from rtc chip\n");
  60. return 0;
  61. }
  62. time = (time << 8) | (tmp & 0xff);
  63. }
  64. return time;
  65. }
  66. static void ds1374_write_rtc(ulong time)
  67. {
  68. int reg;
  69. for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
  70. if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
  71. < 0) {
  72. dev_warn(&save_client->dev,
  73. "can't write to rtc chip\n");
  74. break;
  75. }
  76. time = time >> 8;
  77. }
  78. }
  79. static void ds1374_check_rtc_status(void)
  80. {
  81. s32 tmp;
  82. tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
  83. if (tmp < 0) {
  84. dev_warn(&save_client->dev,
  85. "can't read status from rtc chip\n");
  86. return;
  87. }
  88. if (tmp & DS1374_REG_SR_OSF) {
  89. dev_warn(&save_client->dev,
  90. "oscillator discontinuity flagged, time unreliable\n");
  91. tmp &= ~DS1374_REG_SR_OSF;
  92. tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
  93. tmp & 0xff);
  94. if (tmp < 0)
  95. dev_warn(&save_client->dev,
  96. "can't clear discontinuity notification\n");
  97. }
  98. }
  99. ulong ds1374_get_rtc_time(void)
  100. {
  101. ulong t1, t2;
  102. int limit = 10; /* arbitrary retry limit */
  103. down(&ds1374_mutex);
  104. /*
  105. * Since the reads are being performed one byte at a time using
  106. * the SMBus vs a 4-byte i2c transfer, there is a chance that a
  107. * carry will occur during the read. To detect this, 2 reads are
  108. * performed and compared.
  109. */
  110. do {
  111. t1 = ds1374_read_rtc();
  112. t2 = ds1374_read_rtc();
  113. } while (t1 != t2 && limit--);
  114. up(&ds1374_mutex);
  115. if (t1 != t2) {
  116. dev_warn(&save_client->dev,
  117. "can't get consistent time from rtc chip\n");
  118. t1 = 0;
  119. }
  120. return t1;
  121. }
  122. static void ds1374_set_tlet(ulong arg)
  123. {
  124. ulong t1, t2;
  125. int limit = 10; /* arbitrary retry limit */
  126. t1 = *(ulong *) arg;
  127. down(&ds1374_mutex);
  128. /*
  129. * Since the writes are being performed one byte at a time using
  130. * the SMBus vs a 4-byte i2c transfer, there is a chance that a
  131. * carry will occur during the write. To detect this, the write
  132. * value is read back and compared.
  133. */
  134. do {
  135. ds1374_write_rtc(t1);
  136. t2 = ds1374_read_rtc();
  137. } while (t1 != t2 && limit--);
  138. up(&ds1374_mutex);
  139. if (t1 != t2)
  140. dev_warn(&save_client->dev,
  141. "can't confirm time set from rtc chip\n");
  142. }
  143. ulong new_time;
  144. DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (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 = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
  166. if (!client)
  167. return -ENOMEM;
  168. memset(client, 0, sizeof(struct i2c_client));
  169. strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
  170. client->flags = I2C_DF_NOTIFY;
  171. client->addr = addr;
  172. client->adapter = adap;
  173. client->driver = &ds1374_driver;
  174. if ((rc = i2c_attach_client(client)) != 0) {
  175. kfree(client);
  176. return rc;
  177. }
  178. save_client = client;
  179. ds1374_check_rtc_status();
  180. return 0;
  181. }
  182. static int ds1374_attach(struct i2c_adapter *adap)
  183. {
  184. return i2c_probe(adap, &addr_data, ds1374_probe);
  185. }
  186. static int ds1374_detach(struct i2c_client *client)
  187. {
  188. int rc;
  189. if ((rc = i2c_detach_client(client)) == 0) {
  190. kfree(i2c_get_clientdata(client));
  191. tasklet_kill(&ds1374_tasklet);
  192. }
  193. return rc;
  194. }
  195. static struct i2c_driver ds1374_driver = {
  196. .owner = THIS_MODULE,
  197. .name = DS1374_DRV_NAME,
  198. .id = I2C_DRIVERID_DS1374,
  199. .flags = I2C_DF_NOTIFY,
  200. .attach_adapter = ds1374_attach,
  201. .detach_client = ds1374_detach,
  202. };
  203. static int __init ds1374_init(void)
  204. {
  205. return i2c_add_driver(&ds1374_driver);
  206. }
  207. static void __exit ds1374_exit(void)
  208. {
  209. i2c_del_driver(&ds1374_driver);
  210. }
  211. module_init(ds1374_init);
  212. module_exit(ds1374_exit);
  213. MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>");
  214. MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
  215. MODULE_LICENSE("GPL");