qg-sdam.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #define pr_fmt(fmt) "QG-K: %s: " fmt, __func__
  7. #include <linux/device.h>
  8. #include <linux/of.h>
  9. #include <linux/module.h>
  10. #include <linux/regmap.h>
  11. #include "qg-sdam.h"
  12. #include "qg-reg.h"
  13. static struct qg_sdam *the_chip;
  14. struct qg_sdam_info {
  15. char *name;
  16. u32 offset;
  17. u32 length;
  18. };
  19. static struct qg_sdam_info sdam_info[] = {
  20. [SDAM_VALID] = {
  21. .name = "VALID",
  22. .offset = QG_SDAM_VALID_OFFSET,
  23. .length = 1,
  24. },
  25. [SDAM_SOC] = {
  26. .name = "SOC",
  27. .offset = QG_SDAM_SOC_OFFSET,
  28. .length = 1,
  29. },
  30. [SDAM_TEMP] = {
  31. .name = "BATT_TEMP",
  32. .offset = QG_SDAM_TEMP_OFFSET,
  33. .length = 2,
  34. },
  35. [SDAM_RBAT_MOHM] = {
  36. .name = "RBAT_MOHM",
  37. .offset = QG_SDAM_RBAT_OFFSET,
  38. .length = 2,
  39. },
  40. [SDAM_OCV_UV] = {
  41. .name = "OCV_UV",
  42. .offset = QG_SDAM_OCV_OFFSET,
  43. .length = 4,
  44. },
  45. [SDAM_IBAT_UA] = {
  46. .name = "IBAT_UA",
  47. .offset = QG_SDAM_IBAT_OFFSET,
  48. .length = 4,
  49. },
  50. [SDAM_TIME_SEC] = {
  51. .name = "TIME_SEC",
  52. .offset = QG_SDAM_TIME_OFFSET,
  53. .length = 4,
  54. },
  55. [SDAM_PON_OCV_UV] = {
  56. .name = "SDAM_PON_OCV",
  57. .offset = QG_SDAM_PON_OCV_OFFSET,
  58. .length = 2,
  59. },
  60. [SDAM_ESR_CHARGE_DELTA] = {
  61. .name = "SDAM_ESR_CHARGE_DELTA",
  62. .offset = QG_SDAM_ESR_CHARGE_DELTA_OFFSET,
  63. .length = 4,
  64. },
  65. [SDAM_ESR_DISCHARGE_DELTA] = {
  66. .name = "SDAM_ESR_DISCHARGE_DELTA",
  67. .offset = QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET,
  68. .length = 4,
  69. },
  70. [SDAM_ESR_CHARGE_SF] = {
  71. .name = "SDAM_ESR_CHARGE_SF_OFFSET",
  72. .offset = QG_SDAM_ESR_CHARGE_SF_OFFSET,
  73. .length = 2,
  74. },
  75. [SDAM_ESR_DISCHARGE_SF] = {
  76. .name = "SDAM_ESR_DISCHARGE_SF_OFFSET",
  77. .offset = QG_SDAM_ESR_DISCHARGE_SF_OFFSET,
  78. .length = 2,
  79. },
  80. [SDAM_BATT_AGE_LEVEL] = {
  81. .name = "SDAM_BATT_AGE_LEVEL_OFFSET",
  82. .offset = QG_SDAM_BATT_AGE_LEVEL_OFFSET,
  83. .length = 1,
  84. },
  85. [SDAM_MAGIC] = {
  86. .name = "SDAM_MAGIC_OFFSET",
  87. .offset = QG_SDAM_MAGIC_OFFSET,
  88. .length = 4,
  89. },
  90. [SDAM_FLASH_OCV] = {
  91. .name = "SDAM_FLASH_OCV_OFFSET",
  92. .offset = QG_SDAM_FLASH_OCV_OFFSET,
  93. .length = 1,
  94. },
  95. };
  96. int qg_sdam_write(u8 param, u32 data)
  97. {
  98. int rc;
  99. struct qg_sdam *chip = the_chip;
  100. u32 offset;
  101. size_t length;
  102. if (!chip) {
  103. pr_err("Invalid sdam-chip pointer\n");
  104. return -EINVAL;
  105. }
  106. if (param >= SDAM_MAX) {
  107. pr_err("Invalid SDAM param %d\n", param);
  108. return -EINVAL;
  109. }
  110. offset = chip->sdam_base + sdam_info[param].offset;
  111. length = sdam_info[param].length;
  112. rc = regmap_bulk_write(chip->regmap, offset, (u8 *)&data, length);
  113. if (rc < 0)
  114. pr_err("Failed to write offset=%0x4 param=%d value=%d\n",
  115. offset, param, data);
  116. else
  117. pr_debug("QG SDAM write param=%s value=%d\n",
  118. sdam_info[param].name, data);
  119. return rc;
  120. }
  121. int qg_sdam_read(u8 param, u32 *data)
  122. {
  123. int rc;
  124. struct qg_sdam *chip = the_chip;
  125. u32 offset;
  126. size_t length;
  127. if (!chip) {
  128. pr_err("Invalid sdam-chip pointer\n");
  129. return -EINVAL;
  130. }
  131. if (param >= SDAM_MAX) {
  132. pr_err("Invalid SDAM param %d\n", param);
  133. return -EINVAL;
  134. }
  135. *data = 0;
  136. offset = chip->sdam_base + sdam_info[param].offset;
  137. length = sdam_info[param].length;
  138. rc = regmap_raw_read(chip->regmap, offset, (u8 *)data, length);
  139. if (rc < 0)
  140. pr_err("Failed to read offset=%0x4 param=%d\n",
  141. offset, param);
  142. else
  143. pr_debug("QG SDAM read param=%s value=%d\n",
  144. sdam_info[param].name, *data);
  145. return rc;
  146. }
  147. int qg_sdam_multibyte_write(u32 offset, u8 *data, u32 length)
  148. {
  149. int rc, i;
  150. struct qg_sdam *chip = the_chip;
  151. if (!chip) {
  152. pr_err("Invalid sdam-chip pointer\n");
  153. return -EINVAL;
  154. }
  155. offset = chip->sdam_base + offset;
  156. rc = regmap_bulk_write(chip->regmap, offset, data, (size_t)length);
  157. if (rc < 0) {
  158. pr_err("Failed to write offset=%0x4 value=%d\n",
  159. offset, *data);
  160. } else {
  161. for (i = 0; i < length; i++)
  162. pr_debug("QG SDAM write offset=%0x4 value=%d\n",
  163. offset++, data[i]);
  164. }
  165. return rc;
  166. }
  167. int qg_sdam_multibyte_read(u32 offset, u8 *data, u32 length)
  168. {
  169. int rc, i;
  170. struct qg_sdam *chip = the_chip;
  171. if (!chip) {
  172. pr_err("Invalid sdam-chip pointer\n");
  173. return -EINVAL;
  174. }
  175. offset = chip->sdam_base + offset;
  176. rc = regmap_raw_read(chip->regmap, offset, (u8 *)data, (size_t)length);
  177. if (rc < 0) {
  178. pr_err("Failed to read offset=%0x4\n", offset);
  179. } else {
  180. for (i = 0; i < length; i++)
  181. pr_debug("QG SDAM read offset=%0x4 value=%d\n",
  182. offset++, data[i]);
  183. }
  184. return rc;
  185. }
  186. int qg_sdam_read_all(u32 *sdam_data)
  187. {
  188. int i, rc;
  189. struct qg_sdam *chip = the_chip;
  190. if (!chip) {
  191. pr_err("Invalid sdam-chip pointer\n");
  192. return -EINVAL;
  193. }
  194. for (i = 0; i < SDAM_MAX; i++) {
  195. rc = qg_sdam_read(i, &sdam_data[i]);
  196. if (rc < 0) {
  197. pr_err("Failed to read SDAM param=%s rc=%d\n",
  198. sdam_info[i].name, rc);
  199. return rc;
  200. }
  201. }
  202. return 0;
  203. }
  204. int qg_sdam_write_all(u32 *sdam_data)
  205. {
  206. int i, rc;
  207. struct qg_sdam *chip = the_chip;
  208. if (!chip) {
  209. pr_err("Invalid sdam-chip pointer\n");
  210. return -EINVAL;
  211. }
  212. for (i = 0; i < SDAM_MAX; i++) {
  213. rc = qg_sdam_write(i, sdam_data[i]);
  214. if (rc < 0) {
  215. pr_err("Failed to write SDAM param=%s rc=%d\n",
  216. sdam_info[i].name, rc);
  217. return rc;
  218. }
  219. }
  220. return 0;
  221. }
  222. int qg_sdam_clear(void)
  223. {
  224. int i, rc = 0;
  225. struct qg_sdam *chip = the_chip;
  226. u8 data = 0;
  227. if (!chip) {
  228. pr_err("Invalid sdam-chip pointer\n");
  229. return -EINVAL;
  230. }
  231. for (i = SDAM_MIN_OFFSET; i <= SDAM_MAX_OFFSET; i++)
  232. rc |= qg_sdam_multibyte_write(i, &data, 1);
  233. return rc;
  234. }
  235. int qg_sdam_init(struct device *dev)
  236. {
  237. int rc;
  238. u32 base = 0, type = 0;
  239. struct qg_sdam *chip;
  240. struct device_node *child, *node = dev->of_node;
  241. chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
  242. if (!chip)
  243. return 0;
  244. chip->regmap = dev_get_regmap(dev->parent, NULL);
  245. if (!chip->regmap) {
  246. pr_err("Parent regmap is unavailable\n");
  247. return -ENXIO;
  248. }
  249. /* get the SDAM base address */
  250. for_each_available_child_of_node(node, child) {
  251. rc = of_property_read_u32(child, "reg", &base);
  252. if (rc < 0) {
  253. pr_err("Failed to read base address rc=%d\n", rc);
  254. return rc;
  255. }
  256. rc = regmap_read(chip->regmap, base + PERPH_TYPE_REG, &type);
  257. if (rc < 0) {
  258. pr_err("Failed to read type rc=%d\n", rc);
  259. return rc;
  260. }
  261. switch (type) {
  262. case SDAM_TYPE:
  263. chip->sdam_base = base;
  264. break;
  265. default:
  266. break;
  267. }
  268. }
  269. if (!chip->sdam_base) {
  270. pr_err("QG SDAM node not defined\n");
  271. return -EINVAL;
  272. }
  273. the_chip = chip;
  274. return 0;
  275. }