w1_therm.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. /*
  2. * w1_therm.c
  3. *
  4. * Copyright (c) 2004 Evgeniy Polyakov <[email protected]>
  5. *
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the therms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. #include <asm/types.h>
  22. #include <linux/kernel.h>
  23. #include <linux/module.h>
  24. #include <linux/moduleparam.h>
  25. #include <linux/sched.h>
  26. #include <linux/device.h>
  27. #include <linux/types.h>
  28. #include <linux/slab.h>
  29. #include <linux/delay.h>
  30. #include "../w1.h"
  31. #include "../w1_int.h"
  32. #include "../w1_family.h"
  33. MODULE_LICENSE("GPL");
  34. MODULE_AUTHOR("Evgeniy Polyakov <[email protected]>");
  35. MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
  36. MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS18S20));
  37. MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS1822));
  38. MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS18B20));
  39. MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS1825));
  40. MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS28EA00));
  41. /* Allow the strong pullup to be disabled, but default to enabled.
  42. * If it was disabled a parasite powered device might not get the require
  43. * current to do a temperature conversion. If it is enabled parasite powered
  44. * devices have a better chance of getting the current required.
  45. * In case the parasite power-detection is not working (seems to be the case
  46. * for some DS18S20) the strong pullup can also be forced, regardless of the
  47. * power state of the devices.
  48. *
  49. * Summary of options:
  50. * - strong_pullup = 0 Disable strong pullup completely
  51. * - strong_pullup = 1 Enable automatic strong pullup detection
  52. * - strong_pullup = 2 Force strong pullup
  53. */
  54. static int w1_strong_pullup = 1;
  55. module_param_named(strong_pullup, w1_strong_pullup, int, 0);
  56. struct w1_therm_family_data {
  57. uint8_t rom[9];
  58. atomic_t refcnt;
  59. };
  60. /* return the address of the refcnt in the family data */
  61. #define THERM_REFCNT(family_data) \
  62. (&((struct w1_therm_family_data *)family_data)->refcnt)
  63. static int w1_therm_add_slave(struct w1_slave *sl)
  64. {
  65. sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
  66. GFP_KERNEL);
  67. if (!sl->family_data)
  68. return -ENOMEM;
  69. atomic_set(THERM_REFCNT(sl->family_data), 1);
  70. return 0;
  71. }
  72. static void w1_therm_remove_slave(struct w1_slave *sl)
  73. {
  74. int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
  75. while (refcnt) {
  76. msleep(1000);
  77. refcnt = atomic_read(THERM_REFCNT(sl->family_data));
  78. }
  79. kfree(sl->family_data);
  80. sl->family_data = NULL;
  81. }
  82. static ssize_t w1_slave_show(struct device *device,
  83. struct device_attribute *attr, char *buf);
  84. static ssize_t w1_slave_store(struct device *device,
  85. struct device_attribute *attr, const char *buf, size_t size);
  86. static ssize_t w1_seq_show(struct device *device,
  87. struct device_attribute *attr, char *buf);
  88. static DEVICE_ATTR_RW(w1_slave);
  89. static DEVICE_ATTR_RO(w1_seq);
  90. static struct attribute *w1_therm_attrs[] = {
  91. &dev_attr_w1_slave.attr,
  92. NULL,
  93. };
  94. static struct attribute *w1_ds28ea00_attrs[] = {
  95. &dev_attr_w1_slave.attr,
  96. &dev_attr_w1_seq.attr,
  97. NULL,
  98. };
  99. ATTRIBUTE_GROUPS(w1_therm);
  100. ATTRIBUTE_GROUPS(w1_ds28ea00);
  101. static struct w1_family_ops w1_therm_fops = {
  102. .add_slave = w1_therm_add_slave,
  103. .remove_slave = w1_therm_remove_slave,
  104. .groups = w1_therm_groups,
  105. };
  106. static struct w1_family_ops w1_ds28ea00_fops = {
  107. .add_slave = w1_therm_add_slave,
  108. .remove_slave = w1_therm_remove_slave,
  109. .groups = w1_ds28ea00_groups,
  110. };
  111. static struct w1_family w1_therm_family_DS18S20 = {
  112. .fid = W1_THERM_DS18S20,
  113. .fops = &w1_therm_fops,
  114. };
  115. static struct w1_family w1_therm_family_DS18B20 = {
  116. .fid = W1_THERM_DS18B20,
  117. .fops = &w1_therm_fops,
  118. };
  119. static struct w1_family w1_therm_family_DS1822 = {
  120. .fid = W1_THERM_DS1822,
  121. .fops = &w1_therm_fops,
  122. };
  123. static struct w1_family w1_therm_family_DS28EA00 = {
  124. .fid = W1_THERM_DS28EA00,
  125. .fops = &w1_ds28ea00_fops,
  126. };
  127. static struct w1_family w1_therm_family_DS1825 = {
  128. .fid = W1_THERM_DS1825,
  129. .fops = &w1_therm_fops,
  130. };
  131. struct w1_therm_family_converter {
  132. u8 broken;
  133. u16 reserved;
  134. struct w1_family *f;
  135. int (*convert)(u8 rom[9]);
  136. int (*precision)(struct device *device, int val);
  137. int (*eeprom)(struct device *device);
  138. };
  139. /* write configuration to eeprom */
  140. static inline int w1_therm_eeprom(struct device *device);
  141. /* Set precision for conversion */
  142. static inline int w1_DS18B20_precision(struct device *device, int val);
  143. static inline int w1_DS18S20_precision(struct device *device, int val);
  144. /* The return value is millidegrees Centigrade. */
  145. static inline int w1_DS18B20_convert_temp(u8 rom[9]);
  146. static inline int w1_DS18S20_convert_temp(u8 rom[9]);
  147. static struct w1_therm_family_converter w1_therm_families[] = {
  148. {
  149. .f = &w1_therm_family_DS18S20,
  150. .convert = w1_DS18S20_convert_temp,
  151. .precision = w1_DS18S20_precision,
  152. .eeprom = w1_therm_eeprom
  153. },
  154. {
  155. .f = &w1_therm_family_DS1822,
  156. .convert = w1_DS18B20_convert_temp,
  157. .precision = w1_DS18S20_precision,
  158. .eeprom = w1_therm_eeprom
  159. },
  160. {
  161. .f = &w1_therm_family_DS18B20,
  162. .convert = w1_DS18B20_convert_temp,
  163. .precision = w1_DS18B20_precision,
  164. .eeprom = w1_therm_eeprom
  165. },
  166. {
  167. .f = &w1_therm_family_DS28EA00,
  168. .convert = w1_DS18B20_convert_temp,
  169. .precision = w1_DS18S20_precision,
  170. .eeprom = w1_therm_eeprom
  171. },
  172. {
  173. .f = &w1_therm_family_DS1825,
  174. .convert = w1_DS18B20_convert_temp,
  175. .precision = w1_DS18S20_precision,
  176. .eeprom = w1_therm_eeprom
  177. }
  178. };
  179. static inline int w1_therm_eeprom(struct device *device)
  180. {
  181. struct w1_slave *sl = dev_to_w1_slave(device);
  182. struct w1_master *dev = sl->master;
  183. u8 rom[9], external_power;
  184. int ret, max_trying = 10;
  185. u8 *family_data = sl->family_data;
  186. ret = mutex_lock_interruptible(&dev->bus_mutex);
  187. if (ret != 0)
  188. goto post_unlock;
  189. if (!sl->family_data) {
  190. ret = -ENODEV;
  191. goto pre_unlock;
  192. }
  193. /* prevent the slave from going away in sleep */
  194. atomic_inc(THERM_REFCNT(family_data));
  195. memset(rom, 0, sizeof(rom));
  196. while (max_trying--) {
  197. if (!w1_reset_select_slave(sl)) {
  198. unsigned int tm = 10;
  199. unsigned long sleep_rem;
  200. /* check if in parasite mode */
  201. w1_write_8(dev, W1_READ_PSUPPLY);
  202. external_power = w1_read_8(dev);
  203. if (w1_reset_select_slave(sl))
  204. continue;
  205. /* 10ms strong pullup/delay after the copy command */
  206. if (w1_strong_pullup == 2 ||
  207. (!external_power && w1_strong_pullup))
  208. w1_next_pullup(dev, tm);
  209. w1_write_8(dev, W1_COPY_SCRATCHPAD);
  210. if (external_power) {
  211. mutex_unlock(&dev->bus_mutex);
  212. sleep_rem = msleep_interruptible(tm);
  213. if (sleep_rem != 0) {
  214. ret = -EINTR;
  215. goto post_unlock;
  216. }
  217. ret = mutex_lock_interruptible(&dev->bus_mutex);
  218. if (ret != 0)
  219. goto post_unlock;
  220. } else if (!w1_strong_pullup) {
  221. sleep_rem = msleep_interruptible(tm);
  222. if (sleep_rem != 0) {
  223. ret = -EINTR;
  224. goto pre_unlock;
  225. }
  226. }
  227. break;
  228. }
  229. }
  230. pre_unlock:
  231. mutex_unlock(&dev->bus_mutex);
  232. post_unlock:
  233. atomic_dec(THERM_REFCNT(family_data));
  234. return ret;
  235. }
  236. /* DS18S20 does not feature configuration register */
  237. static inline int w1_DS18S20_precision(struct device *device, int val)
  238. {
  239. return 0;
  240. }
  241. static inline int w1_DS18B20_precision(struct device *device, int val)
  242. {
  243. struct w1_slave *sl = dev_to_w1_slave(device);
  244. struct w1_master *dev = sl->master;
  245. u8 rom[9], crc;
  246. int ret, max_trying = 10;
  247. u8 *family_data = sl->family_data;
  248. uint8_t precision_bits;
  249. uint8_t mask = 0x60;
  250. if (val > 12 || val < 9) {
  251. pr_warn("Unsupported precision\n");
  252. return -1;
  253. }
  254. ret = mutex_lock_interruptible(&dev->bus_mutex);
  255. if (ret != 0)
  256. goto post_unlock;
  257. if (!sl->family_data) {
  258. ret = -ENODEV;
  259. goto pre_unlock;
  260. }
  261. /* prevent the slave from going away in sleep */
  262. atomic_inc(THERM_REFCNT(family_data));
  263. memset(rom, 0, sizeof(rom));
  264. /* translate precision to bitmask (see datasheet page 9) */
  265. switch (val) {
  266. case 9:
  267. precision_bits = 0x00;
  268. break;
  269. case 10:
  270. precision_bits = 0x20;
  271. break;
  272. case 11:
  273. precision_bits = 0x40;
  274. break;
  275. case 12:
  276. default:
  277. precision_bits = 0x60;
  278. break;
  279. }
  280. while (max_trying--) {
  281. crc = 0;
  282. if (!w1_reset_select_slave(sl)) {
  283. int count = 0;
  284. /* read values to only alter precision bits */
  285. w1_write_8(dev, W1_READ_SCRATCHPAD);
  286. count = w1_read_block(dev, rom, 9);
  287. if (count != 9)
  288. dev_warn(device, "w1_read_block() returned %u instead of 9.\n", count);
  289. crc = w1_calc_crc8(rom, 8);
  290. if (rom[8] == crc) {
  291. rom[4] = (rom[4] & ~mask) | (precision_bits & mask);
  292. if (!w1_reset_select_slave(sl)) {
  293. w1_write_8(dev, W1_WRITE_SCRATCHPAD);
  294. w1_write_8(dev, rom[2]);
  295. w1_write_8(dev, rom[3]);
  296. w1_write_8(dev, rom[4]);
  297. break;
  298. }
  299. }
  300. }
  301. }
  302. pre_unlock:
  303. mutex_unlock(&dev->bus_mutex);
  304. post_unlock:
  305. atomic_dec(THERM_REFCNT(family_data));
  306. return ret;
  307. }
  308. static inline int w1_DS18B20_convert_temp(u8 rom[9])
  309. {
  310. s16 t = le16_to_cpup((__le16 *)rom);
  311. return t*1000/16;
  312. }
  313. static inline int w1_DS18S20_convert_temp(u8 rom[9])
  314. {
  315. int t, h;
  316. if (!rom[7])
  317. return 0;
  318. if (rom[1] == 0)
  319. t = ((s32)rom[0] >> 1)*1000;
  320. else
  321. t = 1000*(-1*(s32)(0x100-rom[0]) >> 1);
  322. t -= 250;
  323. h = 1000*((s32)rom[7] - (s32)rom[6]);
  324. h /= (s32)rom[7];
  325. t += h;
  326. return t;
  327. }
  328. static inline int w1_convert_temp(u8 rom[9], u8 fid)
  329. {
  330. int i;
  331. for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i)
  332. if (w1_therm_families[i].f->fid == fid)
  333. return w1_therm_families[i].convert(rom);
  334. return 0;
  335. }
  336. static ssize_t w1_slave_store(struct device *device,
  337. struct device_attribute *attr, const char *buf,
  338. size_t size)
  339. {
  340. int val, ret;
  341. struct w1_slave *sl = dev_to_w1_slave(device);
  342. int i;
  343. ret = kstrtoint(buf, 0, &val);
  344. if (ret)
  345. return ret;
  346. for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
  347. if (w1_therm_families[i].f->fid == sl->family->fid) {
  348. /* zero value indicates to write current configuration to eeprom */
  349. if (val == 0)
  350. ret = w1_therm_families[i].eeprom(device);
  351. else
  352. ret = w1_therm_families[i].precision(device, val);
  353. break;
  354. }
  355. }
  356. return ret ? : size;
  357. }
  358. static ssize_t w1_slave_show(struct device *device,
  359. struct device_attribute *attr, char *buf)
  360. {
  361. struct w1_slave *sl = dev_to_w1_slave(device);
  362. struct w1_master *dev = sl->master;
  363. u8 rom[9], crc, verdict, external_power;
  364. int i, ret, max_trying = 10;
  365. ssize_t c = PAGE_SIZE;
  366. u8 *family_data = sl->family_data;
  367. ret = mutex_lock_interruptible(&dev->bus_mutex);
  368. if (ret != 0)
  369. goto post_unlock;
  370. if (!sl->family_data) {
  371. ret = -ENODEV;
  372. goto pre_unlock;
  373. }
  374. /* prevent the slave from going away in sleep */
  375. atomic_inc(THERM_REFCNT(family_data));
  376. memset(rom, 0, sizeof(rom));
  377. while (max_trying--) {
  378. verdict = 0;
  379. crc = 0;
  380. if (!w1_reset_select_slave(sl)) {
  381. int count = 0;
  382. unsigned int tm = 750;
  383. unsigned long sleep_rem;
  384. w1_write_8(dev, W1_READ_PSUPPLY);
  385. external_power = w1_read_8(dev);
  386. if (w1_reset_select_slave(sl))
  387. continue;
  388. /* 750ms strong pullup (or delay) after the convert */
  389. if (w1_strong_pullup == 2 ||
  390. (!external_power && w1_strong_pullup))
  391. w1_next_pullup(dev, tm);
  392. w1_write_8(dev, W1_CONVERT_TEMP);
  393. if (external_power) {
  394. mutex_unlock(&dev->bus_mutex);
  395. sleep_rem = msleep_interruptible(tm);
  396. if (sleep_rem != 0) {
  397. ret = -EINTR;
  398. goto post_unlock;
  399. }
  400. ret = mutex_lock_interruptible(&dev->bus_mutex);
  401. if (ret != 0)
  402. goto post_unlock;
  403. } else if (!w1_strong_pullup) {
  404. sleep_rem = msleep_interruptible(tm);
  405. if (sleep_rem != 0) {
  406. ret = -EINTR;
  407. goto pre_unlock;
  408. }
  409. }
  410. if (!w1_reset_select_slave(sl)) {
  411. w1_write_8(dev, W1_READ_SCRATCHPAD);
  412. count = w1_read_block(dev, rom, 9);
  413. if (count != 9) {
  414. dev_warn(device, "w1_read_block() "
  415. "returned %u instead of 9.\n",
  416. count);
  417. }
  418. crc = w1_calc_crc8(rom, 8);
  419. if (rom[8] == crc)
  420. verdict = 1;
  421. }
  422. }
  423. if (verdict)
  424. break;
  425. }
  426. for (i = 0; i < 9; ++i)
  427. c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", rom[i]);
  428. c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n",
  429. crc, (verdict) ? "YES" : "NO");
  430. if (verdict)
  431. memcpy(family_data, rom, sizeof(rom));
  432. else
  433. dev_warn(device, "Read failed CRC check\n");
  434. for (i = 0; i < 9; ++i)
  435. c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ",
  436. ((u8 *)family_data)[i]);
  437. c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
  438. w1_convert_temp(rom, sl->family->fid));
  439. ret = PAGE_SIZE - c;
  440. pre_unlock:
  441. mutex_unlock(&dev->bus_mutex);
  442. post_unlock:
  443. atomic_dec(THERM_REFCNT(family_data));
  444. return ret;
  445. }
  446. #define W1_42_CHAIN 0x99
  447. #define W1_42_CHAIN_OFF 0x3C
  448. #define W1_42_CHAIN_OFF_INV 0xC3
  449. #define W1_42_CHAIN_ON 0x5A
  450. #define W1_42_CHAIN_ON_INV 0xA5
  451. #define W1_42_CHAIN_DONE 0x96
  452. #define W1_42_CHAIN_DONE_INV 0x69
  453. #define W1_42_COND_READ 0x0F
  454. #define W1_42_SUCCESS_CONFIRM_BYTE 0xAA
  455. #define W1_42_FINISHED_BYTE 0xFF
  456. static ssize_t w1_seq_show(struct device *device,
  457. struct device_attribute *attr, char *buf)
  458. {
  459. struct w1_slave *sl = dev_to_w1_slave(device);
  460. ssize_t c = PAGE_SIZE;
  461. int rv;
  462. int i;
  463. u8 ack;
  464. u64 rn;
  465. struct w1_reg_num *reg_num;
  466. int seq = 0;
  467. mutex_lock(&sl->master->bus_mutex);
  468. /* Place all devices in CHAIN state */
  469. if (w1_reset_bus(sl->master))
  470. goto error;
  471. w1_write_8(sl->master, W1_SKIP_ROM);
  472. w1_write_8(sl->master, W1_42_CHAIN);
  473. w1_write_8(sl->master, W1_42_CHAIN_ON);
  474. w1_write_8(sl->master, W1_42_CHAIN_ON_INV);
  475. msleep(sl->master->pullup_duration);
  476. /* check for acknowledgment */
  477. ack = w1_read_8(sl->master);
  478. if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
  479. goto error;
  480. /* In case the bus fails to send 0xFF, limit*/
  481. for (i = 0; i <= 64; i++) {
  482. if (w1_reset_bus(sl->master))
  483. goto error;
  484. w1_write_8(sl->master, W1_42_COND_READ);
  485. rv = w1_read_block(sl->master, (u8 *)&rn, 8);
  486. reg_num = (struct w1_reg_num *) &rn;
  487. if (reg_num->family == W1_42_FINISHED_BYTE)
  488. break;
  489. if (sl->reg_num.id == reg_num->id)
  490. seq = i;
  491. w1_write_8(sl->master, W1_42_CHAIN);
  492. w1_write_8(sl->master, W1_42_CHAIN_DONE);
  493. w1_write_8(sl->master, W1_42_CHAIN_DONE_INV);
  494. w1_read_block(sl->master, &ack, sizeof(ack));
  495. /* check for acknowledgment */
  496. ack = w1_read_8(sl->master);
  497. if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
  498. goto error;
  499. }
  500. /* Exit from CHAIN state */
  501. if (w1_reset_bus(sl->master))
  502. goto error;
  503. w1_write_8(sl->master, W1_SKIP_ROM);
  504. w1_write_8(sl->master, W1_42_CHAIN);
  505. w1_write_8(sl->master, W1_42_CHAIN_OFF);
  506. w1_write_8(sl->master, W1_42_CHAIN_OFF_INV);
  507. /* check for acknowledgment */
  508. ack = w1_read_8(sl->master);
  509. if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
  510. goto error;
  511. mutex_unlock(&sl->master->bus_mutex);
  512. c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", seq);
  513. return PAGE_SIZE - c;
  514. error:
  515. mutex_unlock(&sl->master->bus_mutex);
  516. return -EIO;
  517. }
  518. static int __init w1_therm_init(void)
  519. {
  520. int err, i;
  521. for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
  522. err = w1_register_family(w1_therm_families[i].f);
  523. if (err)
  524. w1_therm_families[i].broken = 1;
  525. }
  526. return 0;
  527. }
  528. static void __exit w1_therm_fini(void)
  529. {
  530. int i;
  531. for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i)
  532. if (!w1_therm_families[i].broken)
  533. w1_unregister_family(w1_therm_families[i].f);
  534. }
  535. module_init(w1_therm_init);
  536. module_exit(w1_therm_fini);