hwmsen_helper.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /*
  2. * Copyright(C)2014 MediaTek Inc.
  3. * Modification based on code covered by the below mentioned copyright
  4. * and/or permission notice(S).
  5. */
  6. #include <linux/init.h>
  7. #include <linux/module.h>
  8. #include <linux/kernel.h>
  9. #include <generated/autoconf.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/hwmon-sysfs.h>
  12. #include <linux/types.h>
  13. #include <linux/device.h>
  14. #include <linux/spinlock.h>
  15. #include <linux/uaccess.h>
  16. #include <linux/io.h>
  17. #include <linux/atomic.h>
  18. #include <linux/ctype.h>
  19. #include <hwmsensor.h>
  20. #include <hwmsen_helper.h>
  21. /*----------------------------------------------------------------------------*/
  22. #define hex2int(c) ((c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9))
  23. /*----------------------------------------------------------------------------*/
  24. #define C_MAX_REG_LEN (4)
  25. /*----------------------------------------------------------------------------*/
  26. /* #define HWMSEN_DEBUG */
  27. /******************************************************************************
  28. * Functions
  29. ******************************************************************************/
  30. int hwmsen_set_bits(struct i2c_client *client, u8 addr, u8 bits)
  31. {
  32. int err;
  33. u8 cur, nxt;
  34. err = hwmsen_read_byte(client, addr, &cur);
  35. if (err) {
  36. HWM_ERR("read err: 0x%02X\n", addr);
  37. return -EFAULT;
  38. }
  39. nxt = (cur | bits);
  40. if (nxt ^ cur) {
  41. err = hwmsen_write_byte(client, addr, nxt);
  42. if (err) {
  43. HWM_ERR("write err: 0x%02X\n", addr);
  44. return -EFAULT;
  45. }
  46. }
  47. return 0;
  48. }
  49. /*----------------------------------------------------------------------------*/
  50. EXPORT_SYMBOL_GPL(hwmsen_set_bits);
  51. /*----------------------------------------------------------------------------*/
  52. int hwmsen_clr_bits(struct i2c_client *client, u8 addr, u8 bits)
  53. {
  54. int err;
  55. u8 cur, nxt;
  56. err = hwmsen_read_byte(client, addr, &cur);
  57. if (err) {
  58. HWM_ERR("read err: 0x%02X\n", addr);
  59. return -EFAULT;
  60. }
  61. nxt = cur & (~bits);
  62. if (nxt ^ cur) {
  63. err = hwmsen_write_byte(client, addr, nxt);
  64. if (err) {
  65. HWM_ERR("write err: 0x%02X\n", addr);
  66. return -EFAULT;
  67. }
  68. }
  69. return 0;
  70. }
  71. /*----------------------------------------------------------------------------*/
  72. EXPORT_SYMBOL_GPL(hwmsen_clr_bits);
  73. /*----------------------------------------------------------------------------*/
  74. int hwmsen_read_byte(struct i2c_client *client, u8 addr, u8 *data)
  75. {
  76. u8 beg = addr;
  77. int err;
  78. struct i2c_msg msgs[2] = {
  79. {
  80. .addr = client->addr, .flags = 0,
  81. .len = 1, .buf = &beg
  82. },
  83. {
  84. .addr = client->addr, .flags = I2C_M_RD,
  85. .len = 1, .buf = data,
  86. }
  87. };
  88. if (!client)
  89. return -EINVAL;
  90. err = i2c_transfer(client->adapter, msgs, sizeof(msgs)/sizeof(msgs[0]));
  91. if (err != 2) {
  92. HWM_ERR("i2c_transfer error: (%d %p) %d\n", addr, data, err);
  93. err = -EIO;
  94. }
  95. err = 0;
  96. return err;
  97. }
  98. /*----------------------------------------------------------------------------*/
  99. EXPORT_SYMBOL_GPL(hwmsen_read_byte);
  100. /*----------------------------------------------------------------------------*/
  101. int hwmsen_write_byte(struct i2c_client *client, u8 addr, u8 data)
  102. {
  103. u8 buf[] = {addr, data};
  104. int ret = 0;
  105. ret = i2c_master_send(client, (const char *)buf, sizeof(buf));
  106. if (ret < 0) {
  107. HWM_ERR("send command error!!\n");
  108. return -EFAULT;
  109. }
  110. #if defined(HWMSEN_DEBUG)
  111. HWM_LOG("%s(0x%02X)= %02X\n", __func__, addr, data);
  112. #endif
  113. return 0;
  114. }
  115. /*----------------------------------------------------------------------------*/
  116. EXPORT_SYMBOL_GPL(hwmsen_write_byte);
  117. /*----------------------------------------------------------------------------*/
  118. int hwmsen_read_block(struct i2c_client *client, u8 addr, u8 *data, u8 len)
  119. {
  120. u8 beg = addr;
  121. int err;
  122. struct i2c_msg msgs[2] = {{0}, {0} };
  123. if (len == 1)
  124. return hwmsen_read_byte(client, addr, data);
  125. msgs[0].addr = client->addr;
  126. msgs[0].flags = 0;
  127. msgs[0].len = 1;
  128. msgs[0].buf = &beg;
  129. msgs[1].addr = client->addr;
  130. msgs[1].flags = I2C_M_RD;
  131. msgs[1].len = len;
  132. msgs[1].buf = data;
  133. if (!client)
  134. return -EINVAL;
  135. else if (len > C_I2C_FIFO_SIZE) {
  136. HWM_ERR(" length %d exceeds %d\n", len, C_I2C_FIFO_SIZE);
  137. return -EINVAL;
  138. }
  139. err = i2c_transfer(client->adapter, msgs, sizeof(msgs)/sizeof(msgs[0]));
  140. if (err != 2) {
  141. HWM_ERR("i2c_transfer error: (%d %p %d) %d\n", addr, data, len, err);
  142. err = -EIO;
  143. }
  144. #if defined(HWMSEN_DEBUG)
  145. static char buf[128];
  146. int idx, buflen = 0;
  147. for (idx = 0; idx < len; idx++)
  148. buflen += snprintf(buf+buflen, sizeof(buf)-buflen, "%02X ", data[idx]);
  149. HWM_LOG("%s(0x%02X,%2d) = %s\n", __func__, addr, len, buf);
  150. #endif
  151. err = 0; /*no error*/
  152. return err;
  153. }
  154. EXPORT_SYMBOL_GPL(hwmsen_read_block);
  155. /*----------------------------------------------------------------------------*/
  156. int hwmsen_write_block(struct i2c_client *client, u8 addr, u8 *data, u8 len)
  157. { /*because address also occupies one byte, the maximum length for write is 7 bytes*/
  158. int err, idx, num;
  159. char buf[C_I2C_FIFO_SIZE];
  160. if (!client)
  161. return -EINVAL;
  162. else if (len >= C_I2C_FIFO_SIZE) {
  163. HWM_ERR(" length %d exceeds %d\n", len, C_I2C_FIFO_SIZE);
  164. return -EINVAL;
  165. }
  166. num = 0;
  167. buf[num++] = addr;
  168. for (idx = 0; idx < len; idx++)
  169. buf[num++] = data[idx];
  170. err = i2c_master_send(client, buf, num);
  171. if (err < 0) {
  172. HWM_ERR("send command error!!\n");
  173. return -EFAULT;
  174. }
  175. #if defined(HWMSEN_DEBUG)
  176. static char buf[128];
  177. int idx, buflen = 0;
  178. for (idx = 0; idx < len; idx++)
  179. buflen += snprintf(buf+buflen, sizeof(buf)-buflen, "%02X ", data[idx]);
  180. HWM_LOG("%s(0x%02X,%2d)= %s\n", __func__, addr, len, buf);
  181. #endif
  182. err = 0; /*no error*/
  183. return err;
  184. }
  185. EXPORT_SYMBOL_GPL(hwmsen_write_block);
  186. /*----------------------------------------------------------------------------*/
  187. static int hwmsen_chrs_to_integer(u8 dat[C_MAX_REG_LEN], int datlen)
  188. {
  189. int idx;
  190. u32 val = 0;
  191. for (idx = 0; idx < datlen; idx++)
  192. val += (dat[idx] << (8*idx));
  193. return val;
  194. }
  195. /*----------------------------------------------------------------------------*/
  196. static int hwmsen_byte_to_integer(u8 dat, int datlen)
  197. {
  198. int idx;
  199. u32 val = 0;
  200. for (idx = 0; idx < datlen; idx++)
  201. val += (dat << (8*idx));
  202. return val;
  203. }
  204. /*----------------------------------------------------------------------------*/
  205. void hwmsen_single_rw(struct i2c_client *client,
  206. struct hwmsen_reg *regs, int reg_num)
  207. {
  208. int idx, pos, num, err = 0, cmp1, cmp2;
  209. u8 pattern[] = {0x55, 0xAA};
  210. u8 old[C_MAX_REG_LEN], val[C_MAX_REG_LEN], mask;
  211. struct hwmsen_reg *ptr;
  212. for (idx = 0; idx < reg_num; idx++) {
  213. if (regs[idx].mode != REG_RW)
  214. continue;
  215. if (regs[idx].len > C_MAX_REG_LEN) {
  216. HWM_ERR("exceed maximum length\n");
  217. continue;
  218. }
  219. ptr = &regs[idx];
  220. err = hwmsen_read_block(client, ptr->addr, old, ptr->len);
  221. if (err) {
  222. HWM_ERR("read %s fails\n", ptr->name);
  223. continue;
  224. }
  225. for (pos = 0; pos < sizeof(pattern)/sizeof(pattern[0]); pos++) {
  226. mask = ptr->mask;
  227. for (num = 0; num < ptr->len; num++)
  228. val[num] = pattern[pos] & mask;
  229. err = hwmsen_write_block(client, ptr->addr, val, ptr->len);
  230. if (err) {
  231. HWM_ERR("test: write %s fails, pat[0x%02X]\n", ptr->name, pattern[pos]);
  232. continue;
  233. }
  234. err = hwmsen_read_block(client, ptr->addr, val, ptr->len);
  235. if (err) {
  236. HWM_ERR("test: read %s fails\n", ptr->name);
  237. continue;
  238. }
  239. cmp1 = hwmsen_chrs_to_integer(val, ptr->len);
  240. cmp2 = hwmsen_byte_to_integer(pattern[pos], ptr->len);
  241. if ((cmp1 ^ cmp2) & ptr->mask)
  242. HWM_ERR("test: reg %s[%d] 0x%08X <-> 0x%08X\n", ptr->name, num, cmp1, cmp2);
  243. }
  244. err = hwmsen_write_block(client, ptr->addr, old, ptr->len);
  245. if (err) {
  246. HWM_ERR("restore: write %s\n", ptr->name);
  247. continue;
  248. }
  249. err = hwmsen_read_block(client, ptr->addr, val, ptr->len);
  250. if (err) {
  251. HWM_ERR("restore: read %s\n", ptr->name);
  252. continue;
  253. }
  254. cmp1 = hwmsen_chrs_to_integer(val, ptr->len);
  255. cmp2 = hwmsen_chrs_to_integer(old, ptr->len);
  256. if ((cmp1 ^ cmp2) & ptr->mask) {
  257. HWM_ERR("restore %s fails\n", ptr->name);
  258. err = -EFAULT;
  259. }
  260. }
  261. if (!err)
  262. HWM_VER("hwmsen_single_rw pass!!\n");
  263. }
  264. /*----------------------------------------------------------------------------*/
  265. EXPORT_SYMBOL_GPL(hwmsen_single_rw);
  266. /*----------------------------------------------------------------------------*/
  267. void hwmsen_multi_rw(struct i2c_client *client, find_reg_t findreg,
  268. struct hwmsen_reg_test_multi *items, int inum)
  269. {
  270. u8 pattern[] = {0x55, 0xAA};
  271. u8 buf[C_I2C_FIFO_SIZE], dat[C_I2C_FIFO_SIZE], old[C_I2C_FIFO_SIZE];
  272. int pos, idx, p, err = 0;
  273. for (idx = 0; idx < inum; idx++) {
  274. u8 addr = items[idx].addr;
  275. u8 len = items[idx].len;
  276. u8 mode = items[idx].mode;
  277. for (pos = 0; pos < sizeof(pattern)/sizeof(pattern[0]); pos++) {
  278. err = hwmsen_read_block(client, addr, old, len);
  279. if (err) {
  280. HWM_ERR("(%d) save block fail!!\n", idx);
  281. continue;
  282. }
  283. if (!(mode & REG_WO))
  284. continue;
  285. memset(buf, pattern[pos], sizeof(buf));
  286. for (p = 0; p < len; p++)
  287. buf[p] = buf[p] & findreg(addr+p)->mask;
  288. err = hwmsen_write_block(client, addr, buf, len);
  289. if (err) {
  290. HWM_ERR("(%d) block write fail!!\n", idx);
  291. continue;
  292. }
  293. memset(dat, 0x00, sizeof(dat));
  294. err = hwmsen_read_block(client, addr, dat, len);
  295. if (err) {
  296. HWM_ERR("(%d) block read fail!!\n", idx);
  297. continue;
  298. }
  299. err = hwmsen_write_block(client, addr, old, len);
  300. if (err) {
  301. HWM_ERR("(%d) restore block fail!!\n", idx);
  302. continue;
  303. }
  304. if (memcmp(buf, dat, len)) {
  305. HWM_ERR("(%d) data compare fail!!\n", idx);
  306. HWM_LOG("buf:");
  307. for (p = 0; p < len; p++)
  308. HWM_LOG("%02X", buf[p]);
  309. HWM_LOG("\n");
  310. HWM_LOG("dat:");
  311. for (p = 0; p < len; p++)
  312. HWM_LOG("%02X", dat[p]);
  313. HWM_LOG("\n");
  314. err = 1;
  315. }
  316. }
  317. }
  318. if (!err)
  319. HWM_LOG("%s success : %d cases\n", __func__, inum);
  320. else
  321. HWM_LOG("%s: %d cases\n", __func__, inum);
  322. }
  323. /*----------------------------------------------------------------------------*/
  324. EXPORT_SYMBOL_GPL(hwmsen_multi_rw);
  325. /*----------------------------------------------------------------------------*/
  326. ssize_t hwmsen_show_dump(struct i2c_client *client,
  327. u8 startAddr, u8 *regtbl, u32 regnum,
  328. find_reg_t findreg, char *buf, u32 buflen)
  329. {
  330. int err = 0;
  331. u8 addr = startAddr;
  332. u8 max_len = 8, read_len;
  333. const char *name = NULL;
  334. if (!client)
  335. return -EINVAL;
  336. memset(regtbl, 0x00, regnum);
  337. do {
  338. read_len = ((regnum - addr) > max_len) ? (max_len) : (regnum - addr);
  339. if (!read_len)
  340. break;
  341. err = hwmsen_read_block(client, addr, &regtbl[addr-startAddr], read_len);
  342. if (!err)
  343. addr += read_len;
  344. /* SEN_VER("read block data: %d %d\n", addr, read_len); */
  345. } while (!err);
  346. if (!err) {
  347. int idx;
  348. ssize_t len = 0;
  349. for (idx = startAddr; idx < regnum ; idx++) {
  350. name = findreg(idx)->name;
  351. if (NULL != name)
  352. len += snprintf(buf+len, buflen-len, "%-16s = 0x%02X\n", name, regtbl[idx-startAddr]);
  353. }
  354. return len;
  355. }
  356. return 0;
  357. }
  358. /*----------------------------------------------------------------------------*/
  359. EXPORT_SYMBOL_GPL(hwmsen_show_dump);
  360. /*----------------------------------------------------------------------------*/
  361. ssize_t hwmsen_read_all_regs(struct i2c_client *client, struct hwmsen_reg *regs,
  362. u32 num, char *buf, u32 buflen)
  363. {
  364. int err = 0, pos, idx, val;
  365. struct hwmsen_reg *ptr;
  366. u8 dat[4];
  367. ssize_t len = 0;
  368. if (!client)
  369. return -EINVAL;
  370. for (idx = 0; idx < num; idx++) {
  371. ptr = &regs[idx];
  372. memset(dat, 0x00, sizeof(dat));
  373. if (ptr->len > sizeof(dat)) {
  374. HWM_ERR("exceeds capacity, %d\n", ptr->len);
  375. break;
  376. }
  377. err = hwmsen_read_block(client, ptr->addr, dat, ptr->len);
  378. if (err) {
  379. HWM_ERR("read reg %s (0x%2X) fail!!\n", ptr->name, ptr->addr);
  380. break;
  381. }
  382. val = 0;
  383. for (pos = 0; pos < ptr->len; pos++)
  384. val += (dat[pos] << (8*pos));
  385. len += snprintf(buf+len, buflen-len, "%-16s = %8X\n", ptr->name, val);
  386. }
  387. return (err) ? (0) : len;
  388. }
  389. /*----------------------------------------------------------------------------*/
  390. EXPORT_SYMBOL_GPL(hwmsen_read_all_regs);
  391. /*----------------------------------------------------------------------------*/
  392. ssize_t hwmsen_show_reg(struct i2c_client *client, u8 addr, char *buf, u32 buflen)
  393. {
  394. u8 data = 0;
  395. int err;
  396. err = hwmsen_read_byte(client, addr, &data);
  397. if (err) {
  398. HWM_ERR("reading address 0x%02X fail!!", addr);
  399. return 0;
  400. } else
  401. return snprintf(buf, buflen, "0x%02X\n", data);
  402. }
  403. /*----------------------------------------------------------------------------*/
  404. EXPORT_SYMBOL_GPL(hwmsen_show_reg);
  405. /*----------------------------------------------------------------------------*/
  406. ssize_t hwmsen_store_reg(struct i2c_client *client, u8 addr, const char *buf, size_t count)
  407. {
  408. int err, val;
  409. u8 data;
  410. err = kstrtoint(buf, 16, &val);
  411. if (err != 0) {
  412. HWM_ERR("format not match: (0xAB) <-> '%s'\n", buf);
  413. /* MSG_ERR("format not match: %d %x %x %x %x\n", q-p+1, p[0], p[1], p[2], p[3]); */
  414. return count;
  415. }
  416. data = (u8)val;
  417. err = hwmsen_write_byte(client, addr, data);
  418. if (err)
  419. HWM_ERR("write address 0x%02X fail!!\n", addr);
  420. return count;
  421. }
  422. /*----------------------------------------------------------------------------*/
  423. EXPORT_SYMBOL_GPL(hwmsen_store_reg);
  424. /*----------------------------------------------------------------------------*/
  425. ssize_t hwmsen_show_byte(struct device *dev, struct device_attribute *attr,
  426. char *buf, u32 buflen)
  427. {
  428. int err, index = to_sensor_dev_attr(attr)->index;
  429. struct i2c_client *client = to_i2c_client(dev);
  430. u8 addr = (u8)index;
  431. u8 dat;
  432. err = hwmsen_read_byte(client, addr, &dat);
  433. if (err) {
  434. HWM_ERR("reading address 0x%02X fail!!", addr);
  435. return 0;
  436. }
  437. return snprintf(buf, buflen, "0x%02X\n", dat);
  438. }
  439. /*----------------------------------------------------------------------------*/
  440. EXPORT_SYMBOL_GPL(hwmsen_show_byte);
  441. /*----------------------------------------------------------------------------*/
  442. ssize_t hwmsen_store_byte(struct device *dev, struct device_attribute *attr,
  443. const char *buf, size_t count)
  444. {
  445. int err, val;
  446. int index = to_sensor_dev_attr(attr)->index;
  447. struct i2c_client *client = to_i2c_client(dev);
  448. u8 addr = (u8)index;
  449. u8 dat;
  450. err = kstrtoint(buf, 16, &val);
  451. if (err != 0) {
  452. HWM_ERR("format not match: (0xAB) <-> '%s'\n", buf);
  453. return count;
  454. }
  455. dat = (u8)val;
  456. err = hwmsen_write_byte(client, addr, dat);
  457. if (err)
  458. HWM_ERR("write address 0x%02X fail!!\n", addr);
  459. return count;
  460. }
  461. /*----------------------------------------------------------------------------*/
  462. EXPORT_SYMBOL_GPL(hwmsen_store_byte);
  463. /*----------------------------------------------------------------------------*/
  464. ssize_t hwmsen_show_word(struct device *dev, struct device_attribute *attr,
  465. char *buf, u32 buflen)
  466. {
  467. int err, index = to_sensor_dev_attr(attr)->index;
  468. struct i2c_client *client = to_i2c_client(dev);
  469. u8 addr = (u8)index;
  470. u8 dat[2];
  471. err = hwmsen_read_block(client, addr, dat, sizeof(dat));
  472. if (err) {
  473. HWM_ERR("reading address 0x%02X fail!!", addr);
  474. return 0;
  475. }
  476. return snprintf(buf, buflen, "0x%04X\n", (dat[0] | (dat[1] << 8)));
  477. }
  478. /*----------------------------------------------------------------------------*/
  479. EXPORT_SYMBOL_GPL(hwmsen_show_word);
  480. /*----------------------------------------------------------------------------*/
  481. ssize_t hwmsen_store_word(struct device *dev, struct device_attribute *attr,
  482. const char *buf, size_t count)
  483. {
  484. int err, val;
  485. int index = to_sensor_dev_attr(attr)->index;
  486. struct i2c_client *client = to_i2c_client(dev);
  487. u8 addr = (u8)index;
  488. u8 dat[2];
  489. err = kstrtoint(buf, 16, &val);
  490. if (err != 0) {
  491. HWM_ERR("format not match: (0xAB) <-> '%s'\n", buf);
  492. return count;
  493. }
  494. dat[0] = (u8)((val & 0x00FF));
  495. dat[1] = (u8)((val & 0xFF00) >> 8);
  496. err = hwmsen_write_block(client, addr, dat, sizeof(dat));
  497. if (err)
  498. HWM_ERR("write address 0x%02X fail!!\n", addr);
  499. return count;
  500. }
  501. /*----------------------------------------------------------------------------*/
  502. EXPORT_SYMBOL_GPL(hwmsen_store_word);
  503. /*----------------------------------------------------------------------------*/
  504. struct hwmsen_convert map[] = {
  505. { { 1, 1, 1}, {0, 1, 2} },
  506. { {-1, 1, 1}, {1, 0, 2} },
  507. { {-1, -1, 1}, {0, 1, 2} },
  508. { { 1, -1, 1}, {1, 0, 2} },
  509. { {-1, 1, -1}, {0, 1, 2} },
  510. { { 1, 1, -1}, {1, 0, 2} },
  511. { { 1, -1, -1}, {0, 1, 2} },
  512. { {-1, -1, -1}, {1, 0, 2} },
  513. };
  514. /*----------------------------------------------------------------------------*/
  515. int hwmsen_get_convert(int direction, struct hwmsen_convert *cvt)
  516. {
  517. if (!cvt)
  518. return -EINVAL;
  519. else if (direction >= sizeof(map)/sizeof(map[0]))
  520. return -EINVAL;
  521. *cvt = map[direction];
  522. return 0;
  523. }
  524. /*----------------------------------------------------------------------------*/
  525. EXPORT_SYMBOL_GPL(hwmsen_get_convert);
  526. /*----------------------------------------------------------------------------*/