qg-profile-lib.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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. #include <linux/module.h>
  7. #include <linux/printk.h>
  8. #include <linux/ratelimit.h>
  9. #include "qg-profile-lib.h"
  10. #include "qg-defs.h"
  11. int qg_linear_interpolate(int y0, int x0, int y1, int x1, int x)
  12. {
  13. if (y0 == y1 || x == x0)
  14. return y0;
  15. if (x1 == x0 || x == x1)
  16. return y1;
  17. return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
  18. }
  19. int qg_interpolate_single_row_lut(struct profile_table_data *lut,
  20. int x, int scale)
  21. {
  22. int i, result;
  23. int cols = lut->cols;
  24. if (x < lut->col_entries[0] * scale) {
  25. pr_debug("x %d less than known range return y = %d lut = %s\n",
  26. x, lut->data[0][0], lut->name);
  27. return lut->data[0][0];
  28. }
  29. if (x > lut->col_entries[cols-1] * scale) {
  30. pr_debug("x %d more than known range return y = %d lut = %s\n",
  31. x, lut->data[0][cols-1], lut->name);
  32. return lut->data[0][cols-1];
  33. }
  34. for (i = 0; i < cols; i++) {
  35. if (x <= lut->col_entries[i] * scale)
  36. break;
  37. }
  38. if (x == lut->col_entries[i] * scale) {
  39. result = lut->data[0][i];
  40. } else {
  41. result = qg_linear_interpolate(
  42. lut->data[0][i-1],
  43. lut->col_entries[i-1] * scale,
  44. lut->data[0][i],
  45. lut->col_entries[i] * scale,
  46. x);
  47. }
  48. return result;
  49. }
  50. int qg_interpolate_soc(struct profile_table_data *lut,
  51. int batt_temp, int ocv)
  52. {
  53. int i, j, soc_high, soc_low, soc;
  54. int rows = lut->rows;
  55. int cols = lut->cols;
  56. if (batt_temp < lut->col_entries[0] * DEGC_SCALE) {
  57. pr_debug("batt_temp %d < known temp range\n", batt_temp);
  58. batt_temp = lut->col_entries[0] * DEGC_SCALE;
  59. }
  60. if (batt_temp > lut->col_entries[cols - 1] * DEGC_SCALE) {
  61. pr_debug("batt_temp %d > known temp range\n", batt_temp);
  62. batt_temp = lut->col_entries[cols - 1] * DEGC_SCALE;
  63. }
  64. for (j = 0; j < cols; j++)
  65. if (batt_temp <= lut->col_entries[j] * DEGC_SCALE)
  66. break;
  67. if (batt_temp == lut->col_entries[j] * DEGC_SCALE) {
  68. /* found an exact match for temp in the table */
  69. if (ocv >= lut->data[0][j])
  70. return lut->row_entries[0];
  71. if (ocv <= lut->data[rows - 1][j])
  72. return lut->row_entries[rows - 1];
  73. for (i = 0; i < rows; i++) {
  74. if (ocv >= lut->data[i][j]) {
  75. if (ocv == lut->data[i][j])
  76. return lut->row_entries[i];
  77. soc = qg_linear_interpolate(
  78. lut->row_entries[i],
  79. lut->data[i][j],
  80. lut->row_entries[i - 1],
  81. lut->data[i - 1][j],
  82. ocv);
  83. return soc;
  84. }
  85. }
  86. }
  87. /* batt_temp is within temperature for column j-1 and j */
  88. if (ocv >= lut->data[0][j])
  89. return lut->row_entries[0];
  90. if (ocv <= lut->data[rows - 1][j - 1])
  91. return lut->row_entries[rows - 1];
  92. soc_low = soc_high = 0;
  93. for (i = 0; i < rows-1; i++) {
  94. if (soc_high == 0 && is_between(lut->data[i][j],
  95. lut->data[i+1][j], ocv)) {
  96. soc_high = qg_linear_interpolate(
  97. lut->row_entries[i],
  98. lut->data[i][j],
  99. lut->row_entries[i + 1],
  100. lut->data[i+1][j],
  101. ocv);
  102. }
  103. if (soc_low == 0 && is_between(lut->data[i][j-1],
  104. lut->data[i+1][j-1], ocv)) {
  105. soc_low = qg_linear_interpolate(
  106. lut->row_entries[i],
  107. lut->data[i][j-1],
  108. lut->row_entries[i + 1],
  109. lut->data[i+1][j-1],
  110. ocv);
  111. }
  112. if (soc_high && soc_low) {
  113. soc = qg_linear_interpolate(
  114. soc_low,
  115. lut->col_entries[j-1] * DEGC_SCALE,
  116. soc_high,
  117. lut->col_entries[j] * DEGC_SCALE,
  118. batt_temp);
  119. return soc;
  120. }
  121. }
  122. if (soc_high)
  123. return soc_high;
  124. if (soc_low)
  125. return soc_low;
  126. pr_debug("%d ocv wasn't found for temp %d in the LUT %s returning 100%%\n",
  127. ocv, batt_temp, lut->name);
  128. return 10000;
  129. }
  130. int qg_interpolate_var(struct profile_table_data *lut,
  131. int batt_temp, int soc)
  132. {
  133. int i, var1, var2, var, rows, cols;
  134. int row1 = 0;
  135. int row2 = 0;
  136. rows = lut->rows;
  137. cols = lut->cols;
  138. if (soc > lut->row_entries[0]) {
  139. pr_debug("soc %d greater than known soc ranges for %s lut\n",
  140. soc, lut->name);
  141. row1 = 0;
  142. row2 = 0;
  143. } else if (soc < lut->row_entries[rows - 1]) {
  144. pr_debug("soc %d less than known soc ranges for %s lut\n",
  145. soc, lut->name);
  146. row1 = rows - 1;
  147. row2 = rows - 1;
  148. } else {
  149. for (i = 0; i < rows; i++) {
  150. if (soc == lut->row_entries[i]) {
  151. row1 = i;
  152. row2 = i;
  153. break;
  154. }
  155. if (soc > lut->row_entries[i]) {
  156. row1 = i - 1;
  157. row2 = i;
  158. break;
  159. }
  160. }
  161. }
  162. if (batt_temp < lut->col_entries[0] * DEGC_SCALE)
  163. batt_temp = lut->col_entries[0] * DEGC_SCALE;
  164. if (batt_temp > lut->col_entries[cols - 1] * DEGC_SCALE)
  165. batt_temp = lut->col_entries[cols - 1] * DEGC_SCALE;
  166. for (i = 0; i < cols; i++)
  167. if (batt_temp <= lut->col_entries[i] * DEGC_SCALE)
  168. break;
  169. if (batt_temp == lut->col_entries[i] * DEGC_SCALE) {
  170. var = qg_linear_interpolate(
  171. lut->data[row1][i],
  172. lut->row_entries[row1],
  173. lut->data[row2][i],
  174. lut->row_entries[row2],
  175. soc);
  176. return var;
  177. }
  178. var1 = qg_linear_interpolate(
  179. lut->data[row1][i - 1],
  180. lut->col_entries[i - 1] * DEGC_SCALE,
  181. lut->data[row1][i],
  182. lut->col_entries[i] * DEGC_SCALE,
  183. batt_temp);
  184. var2 = qg_linear_interpolate(
  185. lut->data[row2][i - 1],
  186. lut->col_entries[i - 1] * DEGC_SCALE,
  187. lut->data[row2][i],
  188. lut->col_entries[i] * DEGC_SCALE,
  189. batt_temp);
  190. var = qg_linear_interpolate(
  191. var1,
  192. lut->row_entries[row1],
  193. var2,
  194. lut->row_entries[row2],
  195. soc);
  196. return var;
  197. }
  198. int qg_interpolate_slope(struct profile_table_data *lut,
  199. int batt_temp, int soc)
  200. {
  201. int i, ocvrow1, ocvrow2, rows, cols;
  202. int row1 = 0;
  203. int row2 = 0;
  204. int slope;
  205. rows = lut->rows;
  206. cols = lut->cols;
  207. if (soc >= lut->row_entries[0]) {
  208. pr_debug("soc %d >= max soc range - use the slope at soc=%d for lut %s\n",
  209. soc, lut->row_entries[0], lut->name);
  210. row1 = 0;
  211. row2 = 1;
  212. } else if (soc <= lut->row_entries[rows - 1]) {
  213. pr_debug("soc %d is <= min soc range - use the slope at soc=%d for lut %s\n",
  214. soc, lut->row_entries[rows - 1], lut->name);
  215. row1 = rows - 2;
  216. row2 = rows - 1;
  217. } else {
  218. for (i = 0; i < rows; i++) {
  219. if (soc >= lut->row_entries[i]) {
  220. row1 = i - 1;
  221. row2 = i;
  222. break;
  223. }
  224. }
  225. }
  226. if (batt_temp < lut->col_entries[0] * DEGC_SCALE)
  227. batt_temp = lut->col_entries[0] * DEGC_SCALE;
  228. if (batt_temp > lut->col_entries[cols - 1] * DEGC_SCALE)
  229. batt_temp = lut->col_entries[cols - 1] * DEGC_SCALE;
  230. for (i = 0; i < cols; i++) {
  231. if (batt_temp <= lut->col_entries[i] * DEGC_SCALE)
  232. break;
  233. }
  234. if (batt_temp == lut->col_entries[i] * DEGC_SCALE) {
  235. slope = (lut->data[row1][i] - lut->data[row2][i]);
  236. if (slope <= 0) {
  237. pr_warn_ratelimited("Slope=%d for soc=%d, using 1\n",
  238. slope, soc);
  239. slope = 1;
  240. }
  241. slope *= 10000;
  242. slope /= (lut->row_entries[row1] -
  243. lut->row_entries[row2]);
  244. return slope;
  245. }
  246. ocvrow1 = qg_linear_interpolate(
  247. lut->data[row1][i - 1],
  248. lut->col_entries[i - 1] * DEGC_SCALE,
  249. lut->data[row1][i],
  250. lut->col_entries[i] * DEGC_SCALE,
  251. batt_temp);
  252. ocvrow2 = qg_linear_interpolate(
  253. lut->data[row2][i - 1],
  254. lut->col_entries[i - 1] * DEGC_SCALE,
  255. lut->data[row2][i],
  256. lut->col_entries[i] * DEGC_SCALE,
  257. batt_temp);
  258. slope = (ocvrow1 - ocvrow2);
  259. if (slope <= 0) {
  260. pr_warn_ratelimited("Slope=%d for soc=%d, using 1\n",
  261. slope, soc);
  262. slope = 1;
  263. }
  264. slope *= 10000;
  265. slope /= (lut->row_entries[row1] - lut->row_entries[row2]);
  266. return slope;
  267. }