qti_battery_debug.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  4. */
  5. #define pr_fmt(fmt) "BATTERY_DBG: %s: " fmt, __func__
  6. #include <linux/debugfs.h>
  7. #include <linux/device.h>
  8. #include <linux/module.h>
  9. #include <linux/mutex.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/rpmsg.h>
  12. #include <linux/slab.h>
  13. #include <linux/soc/qcom/pmic_glink.h>
  14. /* owner/type/opcodes for battery debug */
  15. #define MSG_OWNER_BD 32781
  16. #define MSG_TYPE_REQ_RESP 1
  17. #define BD_GET_AGGREGATOR_INFO_REQ 0x15
  18. #define BD_OVERWRITE_VOTABLE_REQ 0x16
  19. #define BD_GET_VOTABLE_REQ 0x17
  20. #define BD_QBG_DUMP_REQ 0x36
  21. /* Generic definitions */
  22. #define MAX_BUF_LEN SZ_4K
  23. #define BD_WAIT_TIME_MS 1000
  24. #define MAX_NUM_VOTABLES 12
  25. #define MAX_NUM_VOTERS 32
  26. #define MAX_NAME_LEN 12
  27. struct all_votables_data {
  28. u32 num_votables;
  29. u32 num_voters;
  30. char votables[MAX_NUM_VOTABLES][MAX_NAME_LEN];
  31. char voters[MAX_NUM_VOTERS][MAX_NAME_LEN];
  32. };
  33. struct votable_data {
  34. u32 votable_id;
  35. u32 eff_val;
  36. u8 voter_ids[MAX_NUM_VOTERS]; /* unused */
  37. u32 votes[MAX_NUM_VOTERS];
  38. u32 active_voter_mask;
  39. u32 eff_voter;
  40. u32 override_voter;
  41. };
  42. struct votable {
  43. char *name;
  44. u32 id;
  45. struct battery_dbg_dev *bd;
  46. struct votable_data data;
  47. u32 override_val;
  48. };
  49. struct qbg_context_req_msg {
  50. struct pmic_glink_hdr hdr;
  51. u32 battery_cell_id;
  52. };
  53. struct qbg_context_resp_msg {
  54. struct pmic_glink_hdr hdr;
  55. u32 length;
  56. u8 buf[MAX_BUF_LEN];
  57. };
  58. struct votables_list_req_msg {
  59. struct pmic_glink_hdr hdr;
  60. };
  61. struct votables_list_resp_msg {
  62. struct pmic_glink_hdr hdr;
  63. struct all_votables_data all_data;
  64. };
  65. struct votable_req_msg {
  66. struct pmic_glink_hdr hdr;
  67. u32 votable_id;
  68. };
  69. struct votable_resp_msg {
  70. struct pmic_glink_hdr hdr;
  71. struct votable_data v_data;
  72. };
  73. struct override_req_msg {
  74. struct pmic_glink_hdr hdr;
  75. u32 votable_id;
  76. u32 override_val;
  77. };
  78. struct battery_dbg_dev {
  79. struct device *dev;
  80. struct pmic_glink_client *client;
  81. struct mutex lock;
  82. struct completion ack;
  83. struct qbg_context_resp_msg qbg_dump;
  84. struct dentry *debugfs_dir;
  85. struct debugfs_blob_wrapper qbg_blob;
  86. struct all_votables_data all_data;
  87. struct votable *votable;
  88. u8 override_voter_id;
  89. u32 battery_cell_id;
  90. };
  91. static int battery_dbg_write(struct battery_dbg_dev *bd, void *data, size_t len)
  92. {
  93. int rc;
  94. mutex_lock(&bd->lock);
  95. reinit_completion(&bd->ack);
  96. rc = pmic_glink_write(bd->client, data, len);
  97. if (!rc) {
  98. rc = wait_for_completion_timeout(&bd->ack,
  99. msecs_to_jiffies(BD_WAIT_TIME_MS));
  100. if (!rc) {
  101. pr_err("Error, timed out sending message\n");
  102. mutex_unlock(&bd->lock);
  103. return -ETIMEDOUT;
  104. }
  105. rc = 0;
  106. }
  107. mutex_unlock(&bd->lock);
  108. return rc;
  109. }
  110. static void handle_qbg_dump_message(struct battery_dbg_dev *bd,
  111. struct qbg_context_resp_msg *resp_msg,
  112. size_t len)
  113. {
  114. u32 buf_len;
  115. if (len > sizeof(bd->qbg_dump)) {
  116. pr_err("Incorrect length received: %zu expected: %u\n", len,
  117. sizeof(bd->qbg_dump));
  118. return;
  119. }
  120. buf_len = resp_msg->length;
  121. if (buf_len > sizeof(bd->qbg_dump.buf)) {
  122. pr_err("Incorrect buffer length: %u\n", buf_len);
  123. return;
  124. }
  125. pr_debug("buf length: %u\n", buf_len);
  126. memcpy(bd->qbg_dump.buf, resp_msg->buf, buf_len);
  127. bd->qbg_blob.size = buf_len;
  128. complete(&bd->ack);
  129. }
  130. static void handle_override_message(struct battery_dbg_dev *bd, void *unused,
  131. size_t len)
  132. {
  133. pr_debug("override succeeded\n");
  134. complete(&bd->ack);
  135. }
  136. static void handle_get_votable_message(struct battery_dbg_dev *bd,
  137. struct votable_resp_msg *resp_msg,
  138. size_t len)
  139. {
  140. u32 id = resp_msg->v_data.votable_id;
  141. if (len != sizeof(*resp_msg)) {
  142. pr_err("Expected data length: %zu, received: %zu\n",
  143. sizeof(*resp_msg), len);
  144. return;
  145. }
  146. if (id >= MAX_NUM_VOTABLES) {
  147. pr_err("Votable id %u exceeds max %d\n", id, MAX_NUM_VOTABLES);
  148. return;
  149. }
  150. if (resp_msg->v_data.active_voter_mask &&
  151. resp_msg->v_data.eff_voter >= MAX_NUM_VOTERS) {
  152. pr_err("Effective voter id %u exceeds max %d\n",
  153. resp_msg->v_data.eff_voter, MAX_NUM_VOTERS);
  154. return;
  155. }
  156. memcpy(&bd->votable[id].data, &resp_msg->v_data,
  157. sizeof(resp_msg->v_data));
  158. complete(&bd->ack);
  159. }
  160. #define OVERRIDE_VOTER_NAME "glink"
  161. static void handle_get_votables_list_message(struct battery_dbg_dev *bd,
  162. struct votables_list_resp_msg *resp_msg,
  163. size_t len)
  164. {
  165. u8 i;
  166. if (len != sizeof(*resp_msg)) {
  167. pr_err("Expected data length: %zu, received: %zu\n",
  168. sizeof(*resp_msg), len);
  169. return;
  170. }
  171. if (resp_msg->all_data.num_votables >= MAX_NUM_VOTABLES) {
  172. pr_err("Num votables %u exceeds max %d\n",
  173. resp_msg->all_data.num_votables, MAX_NUM_VOTABLES);
  174. return;
  175. }
  176. if (resp_msg->all_data.num_voters >= MAX_NUM_VOTERS) {
  177. pr_err("Num voters %u exceeds max %d\n",
  178. resp_msg->all_data.num_voters, MAX_NUM_VOTERS);
  179. return;
  180. }
  181. memcpy(&bd->all_data, &resp_msg->all_data, sizeof(resp_msg->all_data));
  182. for (i = 0; i < MAX_NUM_VOTABLES; i++)
  183. bd->all_data.votables[i][MAX_NAME_LEN - 1] = '\0';
  184. for (i = 0; i < MAX_NUM_VOTERS; i++)
  185. bd->all_data.voters[i][MAX_NAME_LEN - 1] = '\0';
  186. if (!bd->override_voter_id) {
  187. for (i = 0; i < MAX_NUM_VOTERS; i++) {
  188. if (!strcmp(bd->all_data.voters[i],
  189. OVERRIDE_VOTER_NAME)) {
  190. bd->override_voter_id = i;
  191. break;
  192. }
  193. }
  194. }
  195. complete(&bd->ack);
  196. }
  197. static int battery_dbg_callback(void *priv, void *data, size_t len)
  198. {
  199. struct pmic_glink_hdr *hdr = data;
  200. struct battery_dbg_dev *bd = priv;
  201. pr_debug("owner: %u type: %u opcode: %#x len: %zu\n", hdr->owner,
  202. hdr->type, hdr->opcode, len);
  203. switch (hdr->opcode) {
  204. case BD_QBG_DUMP_REQ:
  205. handle_qbg_dump_message(bd, data, len);
  206. break;
  207. case BD_GET_AGGREGATOR_INFO_REQ:
  208. handle_get_votables_list_message(bd, data, len);
  209. break;
  210. case BD_GET_VOTABLE_REQ:
  211. handle_get_votable_message(bd, data, len);
  212. break;
  213. case BD_OVERWRITE_VOTABLE_REQ:
  214. handle_override_message(bd, data, len);
  215. break;
  216. default:
  217. pr_err("Unknown opcode %u\n", hdr->opcode);
  218. break;
  219. }
  220. return 0;
  221. }
  222. #ifdef CONFIG_DEBUG_FS
  223. static int battery_dbg_request_read_votable(struct battery_dbg_dev *bd,
  224. u32 id)
  225. {
  226. struct votable_req_msg req_msg = { { 0 } };
  227. req_msg.hdr.owner = MSG_OWNER_BD;
  228. req_msg.hdr.type = MSG_TYPE_REQ_RESP;
  229. req_msg.hdr.opcode = BD_GET_VOTABLE_REQ;
  230. req_msg.votable_id = id;
  231. return battery_dbg_write(bd, &req_msg, sizeof(req_msg));
  232. }
  233. #ifdef CONFIG_QTI_PMIC_GLINK_CLIENT_DEBUG
  234. static int battery_dbg_request_override(struct battery_dbg_dev *bd, u32 id,
  235. u32 val)
  236. {
  237. struct override_req_msg req_msg = { { 0 } };
  238. req_msg.hdr.owner = MSG_OWNER_BD;
  239. req_msg.hdr.type = MSG_TYPE_REQ_RESP;
  240. req_msg.hdr.opcode = BD_OVERWRITE_VOTABLE_REQ;
  241. req_msg.votable_id = id;
  242. req_msg.override_val = val;
  243. pr_debug("requesting override of %s with value %u\n",
  244. bd->votable[id].name, val);
  245. return battery_dbg_write(bd, &req_msg, sizeof(req_msg));
  246. }
  247. #endif
  248. static int active_show(struct seq_file *s, void *unused)
  249. {
  250. int rc;
  251. unsigned long voter_mask;
  252. struct votable *v = s->private;
  253. struct battery_dbg_dev *bd = v->bd;
  254. rc = battery_dbg_request_read_votable(bd, v->id);
  255. if (rc) {
  256. pr_err("Failed to read %s votable: %d\n", v->name, rc);
  257. return rc;
  258. }
  259. voter_mask = v->data.active_voter_mask;
  260. seq_printf(s, "%#x\n", voter_mask);
  261. return 0;
  262. }
  263. DEFINE_SHOW_ATTRIBUTE(active);
  264. static int winvote_show(struct seq_file *s, void *unused)
  265. {
  266. int rc, winvote;
  267. unsigned long voter_mask;
  268. struct votable *v = s->private;
  269. struct battery_dbg_dev *bd = v->bd;
  270. rc = battery_dbg_request_read_votable(bd, v->id);
  271. if (rc) {
  272. pr_err("Failed to read %s votable: %d\n", v->name, rc);
  273. return rc;
  274. }
  275. voter_mask = v->data.active_voter_mask;
  276. winvote = voter_mask ? v->data.eff_val : -EINVAL;
  277. seq_printf(s, "%d\n", winvote);
  278. return 0;
  279. }
  280. DEFINE_SHOW_ATTRIBUTE(winvote);
  281. static int winner_show(struct seq_file *s, void *unused)
  282. {
  283. int rc;
  284. char *winner;
  285. u32 eff_voter;
  286. unsigned long voter_mask;
  287. struct votable *v = s->private;
  288. struct battery_dbg_dev *bd = v->bd;
  289. rc = battery_dbg_request_read_votable(bd, v->id);
  290. if (rc) {
  291. pr_err("Failed to read %s votable: %d\n", v->name, rc);
  292. return rc;
  293. }
  294. voter_mask = v->data.active_voter_mask;
  295. if (voter_mask) {
  296. eff_voter = v->data.eff_voter;
  297. winner = bd->all_data.voters[eff_voter];
  298. } else {
  299. winner = "";
  300. }
  301. seq_printf(s, "%s\n", winner);
  302. return 0;
  303. }
  304. DEFINE_SHOW_ATTRIBUTE(winner);
  305. static int voters_show(struct seq_file *s, void *unused)
  306. {
  307. int rc, i;
  308. unsigned long voter_mask;
  309. struct votable *v = s->private;
  310. struct battery_dbg_dev *bd = v->bd;
  311. rc = battery_dbg_request_read_votable(bd, v->id);
  312. if (rc) {
  313. pr_err("Failed to read %s votable: %d\n", v->name, rc);
  314. return rc;
  315. }
  316. voter_mask = v->data.active_voter_mask;
  317. for_each_set_bit(i, &voter_mask, MAX_NUM_VOTERS)
  318. seq_printf(s, "%s ", bd->all_data.voters[i]);
  319. seq_puts(s, "\n");
  320. return 0;
  321. }
  322. DEFINE_SHOW_ATTRIBUTE(voters);
  323. static int votes_show(struct seq_file *s, void *unused)
  324. {
  325. int rc, i;
  326. unsigned long voter_mask;
  327. struct votable *v = s->private;
  328. struct battery_dbg_dev *bd = v->bd;
  329. rc = battery_dbg_request_read_votable(bd, v->id);
  330. if (rc) {
  331. pr_err("Failed to read %s votable: %d\n", v->name, rc);
  332. return rc;
  333. }
  334. voter_mask = v->data.active_voter_mask;
  335. for_each_set_bit(i, &voter_mask, MAX_NUM_VOTERS)
  336. seq_printf(s, "%d ", v->data.votes[i]);
  337. seq_puts(s, "\n");
  338. return 0;
  339. }
  340. DEFINE_SHOW_ATTRIBUTE(votes);
  341. static int status_show(struct seq_file *s, void *unused)
  342. {
  343. int rc, i, winvote;
  344. char *winner;
  345. u32 eff_voter;
  346. unsigned long voter_mask;
  347. struct votable *v = s->private;
  348. struct battery_dbg_dev *bd = v->bd;
  349. rc = battery_dbg_request_read_votable(bd, v->id);
  350. if (rc) {
  351. pr_err("Failed to read %s votable: %d\n", v->name, rc);
  352. return rc;
  353. }
  354. voter_mask = v->data.active_voter_mask;
  355. if (!voter_mask) {
  356. seq_puts(s, "\n");
  357. return 0;
  358. }
  359. winvote = v->data.eff_val;
  360. eff_voter = v->data.eff_voter;
  361. winner = bd->all_data.voters[eff_voter];
  362. for_each_set_bit(i, &voter_mask, MAX_NUM_VOTERS)
  363. seq_printf(s, " %-*s: %-*s: %d\n", MAX_NAME_LEN,
  364. v->name, MAX_NAME_LEN, bd->all_data.voters[i],
  365. v->data.votes[i]);
  366. seq_printf(s, "EFFECTIVE: %-*s: %-*s: %d\n", MAX_NAME_LEN, v->name,
  367. MAX_NAME_LEN, winner, winvote);
  368. return 0;
  369. }
  370. DEFINE_SHOW_ATTRIBUTE(status);
  371. #ifdef CONFIG_QTI_PMIC_GLINK_CLIENT_DEBUG
  372. static int override_get(void *data, u64 *val)
  373. {
  374. int rc;
  375. struct votable *v = data;
  376. struct battery_dbg_dev *bd = v->bd;
  377. unsigned long voter_mask;
  378. rc = battery_dbg_request_read_votable(bd, v->id);
  379. if (rc) {
  380. pr_err("Failed to read %s votable: %d\n", v->name, rc);
  381. return rc;
  382. }
  383. voter_mask = v->data.active_voter_mask;
  384. /* Show override voter's vote only if override voter is active */
  385. if (test_bit(bd->override_voter_id, &voter_mask))
  386. *val = v->data.votes[bd->override_voter_id];
  387. else
  388. *val = 0;
  389. return 0;
  390. }
  391. static int override_set(void *data, u64 val)
  392. {
  393. int rc;
  394. struct votable *v = data;
  395. struct battery_dbg_dev *bd = v->bd;
  396. u32 set = val;
  397. rc = battery_dbg_request_override(bd, v->id, set);
  398. if (rc) {
  399. pr_err("%s override request failed: %d\n", v->name, rc);
  400. return rc;
  401. }
  402. return 0;
  403. }
  404. DEFINE_DEBUGFS_ATTRIBUTE(override_fops, override_get, override_set, "%llu\n");
  405. static int battery_dbg_create_override_file(struct votable *v,
  406. struct dentry *votable_dir)
  407. {
  408. return PTR_ERR_OR_ZERO(debugfs_create_file_unsafe("override", 0600,
  409. votable_dir, v, &override_fops));
  410. }
  411. #else
  412. static int battery_dbg_create_override_file(struct votable *v,
  413. struct dentry *votable_dir)
  414. {
  415. return 0;
  416. }
  417. #endif
  418. static int battery_dbg_create_votable(struct battery_dbg_dev *bd,
  419. struct dentry *votables_root_dir,
  420. u32 id)
  421. {
  422. int rc;
  423. char *v_name = bd->all_data.votables[id];
  424. struct dentry *votable_dir;
  425. votable_dir = debugfs_create_dir(v_name, votables_root_dir);
  426. if (IS_ERR(votable_dir)) {
  427. pr_err("Failed to create %s debugfs directory\n", v_name);
  428. return PTR_ERR(votable_dir);
  429. }
  430. bd->votable[id].name = v_name;
  431. rc = PTR_ERR_OR_ZERO(debugfs_create_file("active", 0400, votable_dir,
  432. &bd->votable[id], &active_fops));
  433. if (rc)
  434. goto error;
  435. rc = PTR_ERR_OR_ZERO(debugfs_create_file("winvote", 0400, votable_dir,
  436. &bd->votable[id], &winvote_fops));
  437. if (rc)
  438. goto error;
  439. rc = PTR_ERR_OR_ZERO(debugfs_create_file("winner", 0400, votable_dir,
  440. &bd->votable[id], &winner_fops));
  441. if (rc)
  442. goto error;
  443. rc = PTR_ERR_OR_ZERO(debugfs_create_file("voters", 0400, votable_dir,
  444. &bd->votable[id], &voters_fops));
  445. if (rc)
  446. goto error;
  447. rc = PTR_ERR_OR_ZERO(debugfs_create_file("votes", 0400, votable_dir,
  448. &bd->votable[id], &votes_fops));
  449. if (rc)
  450. goto error;
  451. rc = PTR_ERR_OR_ZERO(debugfs_create_file("status", 0400, votable_dir,
  452. &bd->votable[id], &status_fops));
  453. if (rc)
  454. goto error;
  455. rc = battery_dbg_create_override_file(&bd->votable[id], votable_dir);
  456. if (rc)
  457. goto error;
  458. return 0;
  459. error:
  460. pr_err("Failed to create debugfs file: %d\n", rc);
  461. return rc;
  462. }
  463. static int battery_dbg_get_votables_list(struct battery_dbg_dev *bd)
  464. {
  465. struct votable_req_msg req_msg = { { 0 } };
  466. req_msg.hdr.owner = MSG_OWNER_BD;
  467. req_msg.hdr.type = MSG_TYPE_REQ_RESP;
  468. req_msg.hdr.opcode = BD_GET_AGGREGATOR_INFO_REQ;
  469. return battery_dbg_write(bd, &req_msg, sizeof(req_msg));
  470. }
  471. static int battery_dbg_create_votables(struct battery_dbg_dev *bd,
  472. struct dentry *bd_root_dir)
  473. {
  474. int rc, id;
  475. u32 num_votables;
  476. struct dentry *votables_root_dir;
  477. votables_root_dir = debugfs_create_dir("votables", bd_root_dir);
  478. if (IS_ERR(votables_root_dir)) {
  479. pr_err("Failed to create votables root directory\n");
  480. return PTR_ERR(votables_root_dir);
  481. }
  482. rc = battery_dbg_get_votables_list(bd);
  483. if (rc) {
  484. pr_err("Failed to get votables list: %d\n", rc);
  485. return rc;
  486. }
  487. num_votables = bd->all_data.num_votables;
  488. bd->votable = devm_kcalloc(bd->dev, num_votables,
  489. sizeof(struct votable), GFP_KERNEL);
  490. if (!bd->votable)
  491. return -ENOMEM;
  492. for (id = 0; id < num_votables; id++) {
  493. bd->votable[id].bd = bd;
  494. bd->votable[id].id = id;
  495. rc = battery_dbg_create_votable(bd, votables_root_dir, id);
  496. if (rc)
  497. return rc;
  498. }
  499. return 0;
  500. }
  501. static void battery_dbg_add_debugfs(struct battery_dbg_dev *bd)
  502. {
  503. int rc;
  504. struct dentry *bd_dir;
  505. bd_dir = debugfs_create_dir("battery_debug", NULL);
  506. if (IS_ERR(bd_dir)) {
  507. rc = PTR_ERR(bd_dir);
  508. pr_err("Failed to create battery debugfs directory: %d\n", rc);
  509. return;
  510. }
  511. rc = battery_dbg_create_votables(bd, bd_dir);
  512. if (rc) {
  513. pr_err("Failed to create votables: %d\n", rc);
  514. goto error;
  515. }
  516. bd->debugfs_dir = bd_dir;
  517. return;
  518. error:
  519. debugfs_remove_recursive(bd_dir);
  520. return;
  521. }
  522. #else
  523. static void battery_dbg_add_debugfs(struct battery_dbg_dev *bd)
  524. {
  525. return;
  526. }
  527. #endif
  528. static int get_qbg_context_write(void *data, u64 val)
  529. {
  530. struct battery_dbg_dev *bd = data;
  531. struct qbg_context_req_msg req_msg = { { 0 } };
  532. req_msg.hdr.owner = MSG_OWNER_BD;
  533. req_msg.hdr.type = MSG_TYPE_REQ_RESP;
  534. req_msg.hdr.opcode = BD_QBG_DUMP_REQ;
  535. req_msg.battery_cell_id = bd->battery_cell_id;
  536. return battery_dbg_write(bd, &req_msg, sizeof(req_msg));
  537. }
  538. static ssize_t qbg_blob_write(struct file *filp, struct kobject *kobj,
  539. struct bin_attribute *attr, char *buf,
  540. loff_t pos, size_t count)
  541. {
  542. int rc;
  543. struct device *dev = kobj_to_dev(kobj);
  544. struct battery_dbg_dev *bd = dev_get_drvdata(dev);
  545. rc = get_qbg_context_write(bd, 0); /* second arg is ignored */
  546. if (rc < 0)
  547. return rc;
  548. return count;
  549. }
  550. static ssize_t qbg_blob_read(struct file *filp, struct kobject *kobj,
  551. struct bin_attribute *attr, char *buf,
  552. loff_t pos, size_t count)
  553. {
  554. struct device *dev = kobj_to_dev(kobj);
  555. struct battery_dbg_dev *bd = dev_get_drvdata(dev);
  556. return memory_read_from_buffer(buf, count, &pos, bd->qbg_blob.data,
  557. bd->qbg_blob.size);
  558. }
  559. static struct bin_attribute qbg_blob = {
  560. .attr = {
  561. .name = "qbg_context",
  562. .mode = 0600,
  563. },
  564. .read = qbg_blob_read,
  565. .write = qbg_blob_write,
  566. };
  567. static ssize_t battery_cell_id_show(struct device *dev,
  568. struct device_attribute *attr, char *buf)
  569. {
  570. struct battery_dbg_dev *bd = dev_get_drvdata(dev);
  571. return scnprintf(buf, PAGE_SIZE, "%u\n", bd->battery_cell_id);
  572. }
  573. static ssize_t battery_cell_id_store(struct device *dev,
  574. struct device_attribute *attr, const char *buf,
  575. size_t count)
  576. {
  577. struct battery_dbg_dev *bd = dev_get_drvdata(dev);
  578. if (kstrtou32(buf, 0, &bd->battery_cell_id))
  579. return -EINVAL;
  580. return count;
  581. }
  582. static DEVICE_ATTR_RW(battery_cell_id);
  583. static struct attribute *battery_dbg_attrs[] = {
  584. &dev_attr_battery_cell_id.attr,
  585. NULL,
  586. };
  587. static struct bin_attribute *battery_dbg_bin_attrs[] = {
  588. &qbg_blob,
  589. NULL,
  590. };
  591. static const struct attribute_group battery_dbg_group = {
  592. .attrs = battery_dbg_attrs,
  593. .bin_attrs = battery_dbg_bin_attrs,
  594. };
  595. static int battery_dbg_add_dev_attr(struct battery_dbg_dev *bd)
  596. {
  597. int rc;
  598. bd->qbg_blob.data = bd->qbg_dump.buf;
  599. bd->qbg_blob.size = 0;
  600. rc = sysfs_create_group(&bd->dev->kobj, &battery_dbg_group);
  601. if (rc)
  602. dev_err(bd->dev, "Failed to create sysfs files for qbg_context: %d\n",
  603. rc);
  604. return rc;
  605. }
  606. static int battery_dbg_probe(struct platform_device *pdev)
  607. {
  608. struct battery_dbg_dev *bd;
  609. struct pmic_glink_client_data client_data = { };
  610. int rc;
  611. bd = devm_kzalloc(&pdev->dev, sizeof(*bd), GFP_KERNEL);
  612. if (!bd)
  613. return -ENOMEM;
  614. bd->dev = &pdev->dev;
  615. client_data.id = MSG_OWNER_BD;
  616. client_data.name = "battery_debug";
  617. client_data.msg_cb = battery_dbg_callback;
  618. client_data.priv = bd;
  619. bd->client = pmic_glink_register_client(bd->dev, &client_data);
  620. if (IS_ERR(bd->client)) {
  621. rc = PTR_ERR(bd->client);
  622. if (rc != -EPROBE_DEFER)
  623. dev_err(bd->dev, "Error in registering with pmic_glink %d\n",
  624. rc);
  625. return rc;
  626. }
  627. mutex_init(&bd->lock);
  628. init_completion(&bd->ack);
  629. platform_set_drvdata(pdev, bd);
  630. rc = battery_dbg_add_dev_attr(bd);
  631. if (rc < 0)
  632. goto out;
  633. battery_dbg_add_debugfs(bd);
  634. return 0;
  635. out:
  636. pmic_glink_unregister_client(bd->client);
  637. return rc;
  638. }
  639. static int battery_dbg_remove(struct platform_device *pdev)
  640. {
  641. struct battery_dbg_dev *bd = platform_get_drvdata(pdev);
  642. int rc;
  643. sysfs_remove_group(&bd->dev->kobj, &battery_dbg_group);
  644. debugfs_remove_recursive(bd->debugfs_dir);
  645. rc = pmic_glink_unregister_client(bd->client);
  646. if (rc < 0) {
  647. pr_err("Error unregistering from pmic_glink, rc=%d\n", rc);
  648. return rc;
  649. }
  650. return 0;
  651. }
  652. static const struct of_device_id battery_dbg_match_table[] = {
  653. { .compatible = "qcom,battery-debug" },
  654. {},
  655. };
  656. static struct platform_driver battery_dbg_driver = {
  657. .driver = {
  658. .name = "qti_battery_debug",
  659. .of_match_table = battery_dbg_match_table,
  660. },
  661. .probe = battery_dbg_probe,
  662. .remove = battery_dbg_remove,
  663. };
  664. module_platform_driver(battery_dbg_driver);
  665. MODULE_DESCRIPTION("QTI Glink battery debug driver");
  666. MODULE_LICENSE("GPL v2");