w1_ds2438.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * 1-Wire implementation for the ds2438 chip
  4. *
  5. * Copyright (c) 2017 Mariusz Bialonczyk <[email protected]>
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/device.h>
  10. #include <linux/types.h>
  11. #include <linux/delay.h>
  12. #include <linux/w1.h>
  13. #define W1_FAMILY_DS2438 0x26
  14. #define W1_DS2438_RETRIES 3
  15. /* Memory commands */
  16. #define W1_DS2438_READ_SCRATCH 0xBE
  17. #define W1_DS2438_WRITE_SCRATCH 0x4E
  18. #define W1_DS2438_COPY_SCRATCH 0x48
  19. #define W1_DS2438_RECALL_MEMORY 0xB8
  20. /* Register commands */
  21. #define W1_DS2438_CONVERT_TEMP 0x44
  22. #define W1_DS2438_CONVERT_VOLTAGE 0xB4
  23. #define DS2438_PAGE_SIZE 8
  24. #define DS2438_ADC_INPUT_VAD 0
  25. #define DS2438_ADC_INPUT_VDD 1
  26. #define DS2438_MAX_CONVERSION_TIME 10 /* ms */
  27. /* Page #0 definitions */
  28. #define DS2438_STATUS_REG 0x00 /* Status/Configuration Register */
  29. #define DS2438_STATUS_IAD (1 << 0) /* Current A/D Control Bit */
  30. #define DS2438_STATUS_CA (1 << 1) /* Current Accumulator Configuration */
  31. #define DS2438_STATUS_EE (1 << 2) /* Current Accumulator Shadow Selector bit */
  32. #define DS2438_STATUS_AD (1 << 3) /* Voltage A/D Input Select Bit */
  33. #define DS2438_STATUS_TB (1 << 4) /* Temperature Busy Flag */
  34. #define DS2438_STATUS_NVB (1 << 5) /* Nonvolatile Memory Busy Flag */
  35. #define DS2438_STATUS_ADB (1 << 6) /* A/D Converter Busy Flag */
  36. #define DS2438_TEMP_LSB 0x01
  37. #define DS2438_TEMP_MSB 0x02
  38. #define DS2438_VOLTAGE_LSB 0x03
  39. #define DS2438_VOLTAGE_MSB 0x04
  40. #define DS2438_CURRENT_LSB 0x05
  41. #define DS2438_CURRENT_MSB 0x06
  42. #define DS2438_THRESHOLD 0x07
  43. /* Page #1 definitions */
  44. #define DS2438_ETM_0 0x00
  45. #define DS2438_ETM_1 0x01
  46. #define DS2438_ETM_2 0x02
  47. #define DS2438_ETM_3 0x03
  48. #define DS2438_ICA 0x04
  49. #define DS2438_OFFSET_LSB 0x05
  50. #define DS2438_OFFSET_MSB 0x06
  51. static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf)
  52. {
  53. unsigned int retries = W1_DS2438_RETRIES;
  54. u8 w1_buf[2];
  55. u8 crc;
  56. size_t count;
  57. while (retries--) {
  58. crc = 0;
  59. if (w1_reset_select_slave(sl))
  60. continue;
  61. w1_buf[0] = W1_DS2438_RECALL_MEMORY;
  62. w1_buf[1] = (u8)pageno;
  63. w1_write_block(sl->master, w1_buf, 2);
  64. if (w1_reset_select_slave(sl))
  65. continue;
  66. w1_buf[0] = W1_DS2438_READ_SCRATCH;
  67. w1_buf[1] = (u8)pageno;
  68. w1_write_block(sl->master, w1_buf, 2);
  69. count = w1_read_block(sl->master, buf, DS2438_PAGE_SIZE + 1);
  70. if (count == DS2438_PAGE_SIZE + 1) {
  71. crc = w1_calc_crc8(buf, DS2438_PAGE_SIZE);
  72. /* check for correct CRC */
  73. if ((u8)buf[DS2438_PAGE_SIZE] == crc)
  74. return 0;
  75. }
  76. }
  77. return -1;
  78. }
  79. static int w1_ds2438_get_temperature(struct w1_slave *sl, int16_t *temperature)
  80. {
  81. unsigned int retries = W1_DS2438_RETRIES;
  82. u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
  83. unsigned int tm = DS2438_MAX_CONVERSION_TIME;
  84. unsigned long sleep_rem;
  85. int ret;
  86. mutex_lock(&sl->master->bus_mutex);
  87. while (retries--) {
  88. if (w1_reset_select_slave(sl))
  89. continue;
  90. w1_write_8(sl->master, W1_DS2438_CONVERT_TEMP);
  91. mutex_unlock(&sl->master->bus_mutex);
  92. sleep_rem = msleep_interruptible(tm);
  93. if (sleep_rem != 0) {
  94. ret = -1;
  95. goto post_unlock;
  96. }
  97. if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) {
  98. ret = -1;
  99. goto post_unlock;
  100. }
  101. break;
  102. }
  103. if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
  104. *temperature = (((int16_t) w1_buf[DS2438_TEMP_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_TEMP_LSB]);
  105. ret = 0;
  106. } else
  107. ret = -1;
  108. mutex_unlock(&sl->master->bus_mutex);
  109. post_unlock:
  110. return ret;
  111. }
  112. static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value)
  113. {
  114. unsigned int retries = W1_DS2438_RETRIES;
  115. u8 w1_buf[3];
  116. u8 status;
  117. int perform_write = 0;
  118. while (retries--) {
  119. if (w1_reset_select_slave(sl))
  120. continue;
  121. w1_buf[0] = W1_DS2438_RECALL_MEMORY;
  122. w1_buf[1] = 0x00;
  123. w1_write_block(sl->master, w1_buf, 2);
  124. if (w1_reset_select_slave(sl))
  125. continue;
  126. w1_buf[0] = W1_DS2438_READ_SCRATCH;
  127. w1_buf[1] = 0x00;
  128. w1_write_block(sl->master, w1_buf, 2);
  129. /* reading one byte of result */
  130. status = w1_read_8(sl->master);
  131. /* if bit0=1, set a value to a mask for easy compare */
  132. if (value)
  133. value = mask;
  134. if ((status & mask) == value)
  135. return 0; /* already set as requested */
  136. /* changing bit */
  137. status ^= mask;
  138. perform_write = 1;
  139. break;
  140. }
  141. if (perform_write) {
  142. retries = W1_DS2438_RETRIES;
  143. while (retries--) {
  144. if (w1_reset_select_slave(sl))
  145. continue;
  146. w1_buf[0] = W1_DS2438_WRITE_SCRATCH;
  147. w1_buf[1] = 0x00;
  148. w1_buf[2] = status;
  149. w1_write_block(sl->master, w1_buf, 3);
  150. if (w1_reset_select_slave(sl))
  151. continue;
  152. w1_buf[0] = W1_DS2438_COPY_SCRATCH;
  153. w1_buf[1] = 0x00;
  154. w1_write_block(sl->master, w1_buf, 2);
  155. return 0;
  156. }
  157. }
  158. return -1;
  159. }
  160. static int w1_ds2438_change_offset_register(struct w1_slave *sl, u8 *value)
  161. {
  162. unsigned int retries = W1_DS2438_RETRIES;
  163. u8 w1_buf[9];
  164. u8 w1_page1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
  165. if (w1_ds2438_get_page(sl, 1, w1_page1_buf) == 0) {
  166. memcpy(&w1_buf[2], w1_page1_buf, DS2438_PAGE_SIZE - 1); /* last register reserved */
  167. w1_buf[7] = value[0]; /* change only offset register */
  168. w1_buf[8] = value[1];
  169. while (retries--) {
  170. if (w1_reset_select_slave(sl))
  171. continue;
  172. w1_buf[0] = W1_DS2438_WRITE_SCRATCH;
  173. w1_buf[1] = 0x01; /* write to page 1 */
  174. w1_write_block(sl->master, w1_buf, 9);
  175. if (w1_reset_select_slave(sl))
  176. continue;
  177. w1_buf[0] = W1_DS2438_COPY_SCRATCH;
  178. w1_buf[1] = 0x01;
  179. w1_write_block(sl->master, w1_buf, 2);
  180. return 0;
  181. }
  182. }
  183. return -1;
  184. }
  185. static int w1_ds2438_get_voltage(struct w1_slave *sl,
  186. int adc_input, uint16_t *voltage)
  187. {
  188. unsigned int retries = W1_DS2438_RETRIES;
  189. u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
  190. unsigned int tm = DS2438_MAX_CONVERSION_TIME;
  191. unsigned long sleep_rem;
  192. int ret;
  193. mutex_lock(&sl->master->bus_mutex);
  194. if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_AD, adc_input)) {
  195. ret = -1;
  196. goto pre_unlock;
  197. }
  198. while (retries--) {
  199. if (w1_reset_select_slave(sl))
  200. continue;
  201. w1_write_8(sl->master, W1_DS2438_CONVERT_VOLTAGE);
  202. mutex_unlock(&sl->master->bus_mutex);
  203. sleep_rem = msleep_interruptible(tm);
  204. if (sleep_rem != 0) {
  205. ret = -1;
  206. goto post_unlock;
  207. }
  208. if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) {
  209. ret = -1;
  210. goto post_unlock;
  211. }
  212. break;
  213. }
  214. if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
  215. *voltage = (((uint16_t) w1_buf[DS2438_VOLTAGE_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_VOLTAGE_LSB]);
  216. ret = 0;
  217. } else
  218. ret = -1;
  219. pre_unlock:
  220. mutex_unlock(&sl->master->bus_mutex);
  221. post_unlock:
  222. return ret;
  223. }
  224. static int w1_ds2438_get_current(struct w1_slave *sl, int16_t *voltage)
  225. {
  226. u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
  227. int ret;
  228. mutex_lock(&sl->master->bus_mutex);
  229. if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
  230. /* The voltage measured across current sense resistor RSENS. */
  231. *voltage = (((int16_t) w1_buf[DS2438_CURRENT_MSB]) << 8) | ((int16_t) w1_buf[DS2438_CURRENT_LSB]);
  232. ret = 0;
  233. } else
  234. ret = -1;
  235. mutex_unlock(&sl->master->bus_mutex);
  236. return ret;
  237. }
  238. static ssize_t iad_write(struct file *filp, struct kobject *kobj,
  239. struct bin_attribute *bin_attr, char *buf,
  240. loff_t off, size_t count)
  241. {
  242. struct w1_slave *sl = kobj_to_w1_slave(kobj);
  243. int ret;
  244. if (count != 1 || off != 0)
  245. return -EFAULT;
  246. mutex_lock(&sl->master->bus_mutex);
  247. if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_IAD, *buf & 0x01) == 0)
  248. ret = 1;
  249. else
  250. ret = -EIO;
  251. mutex_unlock(&sl->master->bus_mutex);
  252. return ret;
  253. }
  254. static ssize_t iad_read(struct file *filp, struct kobject *kobj,
  255. struct bin_attribute *bin_attr, char *buf,
  256. loff_t off, size_t count)
  257. {
  258. struct w1_slave *sl = kobj_to_w1_slave(kobj);
  259. int ret;
  260. int16_t voltage;
  261. if (off != 0)
  262. return 0;
  263. if (!buf)
  264. return -EINVAL;
  265. if (w1_ds2438_get_current(sl, &voltage) == 0)
  266. ret = snprintf(buf, count, "%i\n", voltage);
  267. else
  268. ret = -EIO;
  269. return ret;
  270. }
  271. static ssize_t page0_read(struct file *filp, struct kobject *kobj,
  272. struct bin_attribute *bin_attr, char *buf,
  273. loff_t off, size_t count)
  274. {
  275. struct w1_slave *sl = kobj_to_w1_slave(kobj);
  276. int ret;
  277. u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
  278. if (off != 0)
  279. return 0;
  280. if (!buf)
  281. return -EINVAL;
  282. mutex_lock(&sl->master->bus_mutex);
  283. /* Read no more than page0 size */
  284. if (count > DS2438_PAGE_SIZE)
  285. count = DS2438_PAGE_SIZE;
  286. if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) {
  287. memcpy(buf, &w1_buf, count);
  288. ret = count;
  289. } else
  290. ret = -EIO;
  291. mutex_unlock(&sl->master->bus_mutex);
  292. return ret;
  293. }
  294. static ssize_t page1_read(struct file *filp, struct kobject *kobj,
  295. struct bin_attribute *bin_attr, char *buf,
  296. loff_t off, size_t count)
  297. {
  298. struct w1_slave *sl = kobj_to_w1_slave(kobj);
  299. int ret;
  300. u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
  301. if (off != 0)
  302. return 0;
  303. if (!buf)
  304. return -EINVAL;
  305. mutex_lock(&sl->master->bus_mutex);
  306. /* Read no more than page1 size */
  307. if (count > DS2438_PAGE_SIZE)
  308. count = DS2438_PAGE_SIZE;
  309. if (w1_ds2438_get_page(sl, 1, w1_buf) == 0) {
  310. memcpy(buf, &w1_buf, count);
  311. ret = count;
  312. } else
  313. ret = -EIO;
  314. mutex_unlock(&sl->master->bus_mutex);
  315. return ret;
  316. }
  317. static ssize_t offset_write(struct file *filp, struct kobject *kobj,
  318. struct bin_attribute *bin_attr, char *buf,
  319. loff_t off, size_t count)
  320. {
  321. struct w1_slave *sl = kobj_to_w1_slave(kobj);
  322. int ret;
  323. mutex_lock(&sl->master->bus_mutex);
  324. if (w1_ds2438_change_offset_register(sl, buf) == 0)
  325. ret = count;
  326. else
  327. ret = -EIO;
  328. mutex_unlock(&sl->master->bus_mutex);
  329. return ret;
  330. }
  331. static ssize_t temperature_read(struct file *filp, struct kobject *kobj,
  332. struct bin_attribute *bin_attr, char *buf,
  333. loff_t off, size_t count)
  334. {
  335. struct w1_slave *sl = kobj_to_w1_slave(kobj);
  336. int ret;
  337. int16_t temp;
  338. if (off != 0)
  339. return 0;
  340. if (!buf)
  341. return -EINVAL;
  342. if (w1_ds2438_get_temperature(sl, &temp) == 0)
  343. ret = snprintf(buf, count, "%i\n", temp);
  344. else
  345. ret = -EIO;
  346. return ret;
  347. }
  348. static ssize_t vad_read(struct file *filp, struct kobject *kobj,
  349. struct bin_attribute *bin_attr, char *buf,
  350. loff_t off, size_t count)
  351. {
  352. struct w1_slave *sl = kobj_to_w1_slave(kobj);
  353. int ret;
  354. uint16_t voltage;
  355. if (off != 0)
  356. return 0;
  357. if (!buf)
  358. return -EINVAL;
  359. if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0)
  360. ret = snprintf(buf, count, "%u\n", voltage);
  361. else
  362. ret = -EIO;
  363. return ret;
  364. }
  365. static ssize_t vdd_read(struct file *filp, struct kobject *kobj,
  366. struct bin_attribute *bin_attr, char *buf,
  367. loff_t off, size_t count)
  368. {
  369. struct w1_slave *sl = kobj_to_w1_slave(kobj);
  370. int ret;
  371. uint16_t voltage;
  372. if (off != 0)
  373. return 0;
  374. if (!buf)
  375. return -EINVAL;
  376. if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0)
  377. ret = snprintf(buf, count, "%u\n", voltage);
  378. else
  379. ret = -EIO;
  380. return ret;
  381. }
  382. static BIN_ATTR_RW(iad, 0);
  383. static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE);
  384. static BIN_ATTR_RO(page1, DS2438_PAGE_SIZE);
  385. static BIN_ATTR_WO(offset, 2);
  386. static BIN_ATTR_RO(temperature, 0/* real length varies */);
  387. static BIN_ATTR_RO(vad, 0/* real length varies */);
  388. static BIN_ATTR_RO(vdd, 0/* real length varies */);
  389. static struct bin_attribute *w1_ds2438_bin_attrs[] = {
  390. &bin_attr_iad,
  391. &bin_attr_page0,
  392. &bin_attr_page1,
  393. &bin_attr_offset,
  394. &bin_attr_temperature,
  395. &bin_attr_vad,
  396. &bin_attr_vdd,
  397. NULL,
  398. };
  399. static const struct attribute_group w1_ds2438_group = {
  400. .bin_attrs = w1_ds2438_bin_attrs,
  401. };
  402. static const struct attribute_group *w1_ds2438_groups[] = {
  403. &w1_ds2438_group,
  404. NULL,
  405. };
  406. static const struct w1_family_ops w1_ds2438_fops = {
  407. .groups = w1_ds2438_groups,
  408. };
  409. static struct w1_family w1_ds2438_family = {
  410. .fid = W1_FAMILY_DS2438,
  411. .fops = &w1_ds2438_fops,
  412. };
  413. module_w1_family(w1_ds2438_family);
  414. MODULE_LICENSE("GPL");
  415. MODULE_AUTHOR("Mariusz Bialonczyk <[email protected]>");
  416. MODULE_DESCRIPTION("1-wire driver for Maxim/Dallas DS2438 Smart Battery Monitor");
  417. MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2438));