battery_current_limit.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #define pr_fmt(fmt) "%s: " fmt, __func__
  14. #include <linux/module.h>
  15. #include <linux/moduleparam.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/errno.h>
  18. #include <linux/device.h>
  19. #include <linux/power_supply.h>
  20. #include <linux/delay.h>
  21. #include <linux/slab.h>
  22. #define BCL_DEV_NAME "battery_current_limit"
  23. #define BCL_NAME_LENGTH 20
  24. /*
  25. * Default BCL poll interval 1000 msec
  26. */
  27. #define BCL_POLL_INTERVAL 1000
  28. /*
  29. * Mininum BCL poll interval 10 msec
  30. */
  31. #define MIN_BCL_POLL_INTERVAL 10
  32. #define BATTERY_VOLTAGE_MIN 3400
  33. static const char bcl_type[] = "bcl";
  34. /*
  35. * Battery Current Limit Enable or Not
  36. */
  37. enum bcl_device_mode {
  38. BCL_DEVICE_DISABLED = 0,
  39. BCL_DEVICE_ENABLED,
  40. };
  41. /*
  42. * Battery Current Limit Iavail Threshold Mode set
  43. */
  44. enum bcl_iavail_threshold_mode {
  45. BCL_IAVAIL_THRESHOLD_DISABLED = 0,
  46. BCL_IAVAIL_THRESHOLD_ENABLED,
  47. };
  48. /*
  49. * Battery Current Limit Iavail Threshold Mode
  50. */
  51. enum bcl_iavail_threshold_type {
  52. BCL_IAVAIL_LOW_THRESHOLD_TYPE = 0,
  53. BCL_IAVAIL_HIGH_THRESHOLD_TYPE,
  54. BCL_IAVAIL_THRESHOLD_TYPE_MAX,
  55. };
  56. /**
  57. * BCL control block
  58. *
  59. */
  60. struct bcl_context {
  61. /* BCL device */
  62. struct device *dev;
  63. /* BCL related config parameter */
  64. /* BCL mode enable or not */
  65. enum bcl_device_mode bcl_mode;
  66. /* BCL Iavail Threshold Activate or Not */
  67. enum bcl_iavail_threshold_mode
  68. bcl_threshold_mode[BCL_IAVAIL_THRESHOLD_TYPE_MAX];
  69. /* BCL Iavail Threshold value in milli Amp */
  70. int bcl_threshold_value_ma[BCL_IAVAIL_THRESHOLD_TYPE_MAX];
  71. /* BCL Type */
  72. char bcl_type[BCL_NAME_LENGTH];
  73. /* BCL poll in msec */
  74. int bcl_poll_interval_msec;
  75. /* BCL realtime value based on poll */
  76. /* BCL realtime vbat in mV*/
  77. int bcl_vbat_mv;
  78. /* BCL realtime rbat in mOhms*/
  79. int bcl_rbat_mohm;
  80. /*BCL realtime iavail in milli Amp*/
  81. int bcl_iavail;
  82. /*BCL vbatt min in mV*/
  83. int bcl_vbat_min;
  84. /* BCL period poll delay work structure */
  85. struct delayed_work bcl_iavail_work;
  86. };
  87. static struct bcl_context *gbcl;
  88. static int bcl_get_battery_voltage(int *vbatt_mv)
  89. {
  90. static struct power_supply *psy;
  91. union power_supply_propval ret = {0,};
  92. if (psy == NULL) {
  93. psy = power_supply_get_by_name("battery");
  94. if (psy == NULL) {
  95. pr_err("failed to get ps battery\n");
  96. return -EINVAL;
  97. }
  98. }
  99. if (psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret))
  100. return -EINVAL;
  101. if (ret.intval <= 0)
  102. return -EINVAL;
  103. *vbatt_mv = ret.intval / 1000;
  104. return 0;
  105. }
  106. static int bcl_get_resistance(int *rbatt_mohm)
  107. {
  108. static struct power_supply *psy;
  109. union power_supply_propval ret = {0,};
  110. if (psy == NULL) {
  111. psy = power_supply_get_by_name("bms");
  112. if (psy == NULL) {
  113. pr_err("failed to get ps bms\n");
  114. return -EINVAL;
  115. }
  116. }
  117. if (psy->get_property(psy, POWER_SUPPLY_PROP_RESISTANCE, &ret))
  118. return -EINVAL;
  119. if (ret.intval <= 0)
  120. return -EINVAL;
  121. *rbatt_mohm = ret.intval / 1000;
  122. return 0;
  123. }
  124. /*
  125. * BCL iavail calculation and trigger notification to user space
  126. * if iavail cross threshold
  127. */
  128. static void bcl_calculate_iavail_trigger(void)
  129. {
  130. int iavail_ma = 0;
  131. int vbatt_mv;
  132. int rbatt_mohm;
  133. bool threshold_cross = false;
  134. if (!gbcl) {
  135. pr_err("called before initialization\n");
  136. return;
  137. }
  138. if (bcl_get_battery_voltage(&vbatt_mv))
  139. return;
  140. if (bcl_get_resistance(&rbatt_mohm))
  141. return;
  142. iavail_ma = (vbatt_mv - gbcl->bcl_vbat_min) * 1000 / rbatt_mohm;
  143. gbcl->bcl_rbat_mohm = rbatt_mohm;
  144. gbcl->bcl_vbat_mv = vbatt_mv;
  145. gbcl->bcl_iavail = iavail_ma;
  146. pr_debug("iavail %d, vbatt %d rbatt %d\n", iavail_ma, vbatt_mv,
  147. rbatt_mohm);
  148. if ((gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] ==
  149. BCL_IAVAIL_THRESHOLD_ENABLED)
  150. && (iavail_ma >=
  151. gbcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]))
  152. threshold_cross = true;
  153. else if ((gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
  154. == BCL_IAVAIL_THRESHOLD_ENABLED)
  155. && (iavail_ma <=
  156. gbcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE]))
  157. threshold_cross = true;
  158. if (threshold_cross)
  159. sysfs_notify(&gbcl->dev->kobj, NULL, "type");
  160. }
  161. /*
  162. * BCL iavail work
  163. */
  164. static void bcl_iavail_work(struct work_struct *work)
  165. {
  166. struct bcl_context *bcl = container_of(work,
  167. struct bcl_context, bcl_iavail_work.work);
  168. if (gbcl->bcl_mode == BCL_DEVICE_ENABLED) {
  169. bcl_calculate_iavail_trigger();
  170. /* restart the delay work for caculating imax */
  171. schedule_delayed_work(&bcl->bcl_iavail_work,
  172. msecs_to_jiffies(bcl->bcl_poll_interval_msec));
  173. }
  174. }
  175. /*
  176. * Set BCL mode
  177. */
  178. static void bcl_mode_set(enum bcl_device_mode mode)
  179. {
  180. if (!gbcl)
  181. return;
  182. if (gbcl->bcl_mode == mode)
  183. return;
  184. if (gbcl->bcl_mode == BCL_DEVICE_DISABLED
  185. && mode == BCL_DEVICE_ENABLED) {
  186. gbcl->bcl_mode = mode;
  187. bcl_iavail_work(&(gbcl->bcl_iavail_work.work));
  188. return;
  189. } else if (gbcl->bcl_mode == BCL_DEVICE_ENABLED
  190. && mode == BCL_DEVICE_DISABLED) {
  191. gbcl->bcl_mode = mode;
  192. cancel_delayed_work_sync(&(gbcl->bcl_iavail_work));
  193. return;
  194. }
  195. return;
  196. }
  197. #define show_bcl(name, variable, format) \
  198. static ssize_t \
  199. name##_show(struct device *dev, struct device_attribute *attr, char *buf) \
  200. { \
  201. if (gbcl) \
  202. return snprintf(buf, PAGE_SIZE, format, gbcl->variable); \
  203. else \
  204. return -EPERM; \
  205. }
  206. show_bcl(type, bcl_type, "%s\n")
  207. show_bcl(vbat, bcl_vbat_mv, "%d\n")
  208. show_bcl(rbat, bcl_rbat_mohm, "%d\n")
  209. show_bcl(iavail, bcl_iavail, "%d\n")
  210. show_bcl(vbat_min, bcl_vbat_min, "%d\n");
  211. show_bcl(poll_interval, bcl_poll_interval_msec, "%d\n")
  212. static ssize_t
  213. mode_show(struct device *dev, struct device_attribute *attr, char *buf)
  214. {
  215. if (!gbcl)
  216. return -EPERM;
  217. return snprintf(buf, PAGE_SIZE, "%s\n",
  218. gbcl->bcl_mode == BCL_DEVICE_ENABLED ? "enabled"
  219. : "disabled");
  220. }
  221. static ssize_t
  222. mode_store(struct device *dev, struct device_attribute *attr,
  223. const char *buf, size_t count)
  224. {
  225. if (!gbcl)
  226. return -EPERM;
  227. if (!strncmp(buf, "enabled", 7))
  228. bcl_mode_set(BCL_DEVICE_ENABLED);
  229. else if (!strncmp(buf, "disabled", 8))
  230. bcl_mode_set(BCL_DEVICE_DISABLED);
  231. else
  232. return -EINVAL;
  233. return count;
  234. }
  235. static ssize_t
  236. poll_interval_store(struct device *dev,
  237. struct device_attribute *attr,
  238. const char *buf, size_t count)
  239. {
  240. int value;
  241. if (!gbcl)
  242. return -EPERM;
  243. if (!sscanf(buf, "%d", &value))
  244. return -EINVAL;
  245. if (value < MIN_BCL_POLL_INTERVAL)
  246. return -EINVAL;
  247. gbcl->bcl_poll_interval_msec = value;
  248. return count;
  249. }
  250. static ssize_t vbat_min_store(struct device *dev,
  251. struct device_attribute *attr,
  252. const char *buf, size_t count)
  253. {
  254. int value;
  255. int ret;
  256. if (!gbcl)
  257. return -EPERM;
  258. ret = kstrtoint(buf, 10, &value);
  259. if (ret || (value < 0)) {
  260. pr_err("Incorrect vbatt min value\n");
  261. return -EINVAL;
  262. }
  263. gbcl->bcl_vbat_min = value;
  264. return count;
  265. }
  266. static ssize_t iavail_low_threshold_mode_show(struct device *dev,
  267. struct device_attribute *attr, char *buf)
  268. {
  269. if (!gbcl)
  270. return -EPERM;
  271. return snprintf(buf, PAGE_SIZE, "%s\n",
  272. gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
  273. == BCL_IAVAIL_THRESHOLD_ENABLED ? "enabled" : "disabled");
  274. }
  275. static ssize_t iavail_low_threshold_mode_store(struct device *dev,
  276. struct device_attribute *attr,
  277. const char *buf, size_t count)
  278. {
  279. if (!gbcl)
  280. return -EPERM;
  281. if (!strncmp(buf, "enabled", 7))
  282. gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
  283. = BCL_IAVAIL_THRESHOLD_ENABLED;
  284. else if (!strncmp(buf, "disabled", 7))
  285. gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
  286. = BCL_IAVAIL_THRESHOLD_DISABLED;
  287. else
  288. return -EINVAL;
  289. return count;
  290. }
  291. static ssize_t iavail_high_threshold_mode_show(struct device *dev,
  292. struct device_attribute *attr, char *buf)
  293. {
  294. if (!gbcl)
  295. return -EPERM;
  296. return snprintf(buf, PAGE_SIZE, "%s\n",
  297. gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]
  298. == BCL_IAVAIL_THRESHOLD_ENABLED ? "enabled" : "disabled");
  299. }
  300. static ssize_t iavail_high_threshold_mode_store(struct device *dev,
  301. struct device_attribute *attr,
  302. const char *buf, size_t count)
  303. {
  304. if (!gbcl)
  305. return -EPERM;
  306. if (!strncmp(buf, "enabled", 7))
  307. gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]
  308. = BCL_IAVAIL_THRESHOLD_ENABLED;
  309. else if (!strncmp(buf, "disabled", 7))
  310. gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]
  311. = BCL_IAVAIL_THRESHOLD_DISABLED;
  312. else
  313. return -EINVAL;
  314. return count;
  315. }
  316. static ssize_t iavail_low_threshold_value_show(struct device *dev,
  317. struct device_attribute *attr, char *buf)
  318. {
  319. if (!gbcl)
  320. return -EPERM;
  321. return snprintf(buf, PAGE_SIZE, "%d\n",
  322. gbcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE]);
  323. }
  324. static ssize_t iavail_low_threshold_value_store(struct device *dev,
  325. struct device_attribute *attr,
  326. const char *buf, size_t count)
  327. {
  328. int val;
  329. int ret;
  330. ret = kstrtoint(buf, 10, &val);
  331. if (ret || (val < 0)) {
  332. pr_err("Incorrect available current threshold value\n");
  333. return -EINVAL;
  334. }
  335. gbcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE] = val;
  336. return count;
  337. }
  338. static ssize_t iavail_high_threshold_value_show(struct device *dev,
  339. struct device_attribute *attr, char *buf)
  340. {
  341. if (!gbcl)
  342. return -EPERM;
  343. return snprintf(buf, PAGE_SIZE, "%d\n",
  344. gbcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]);
  345. }
  346. static ssize_t iavail_high_threshold_value_store(struct device *dev,
  347. struct device_attribute *attr,
  348. const char *buf, size_t count)
  349. {
  350. int val;
  351. int ret;
  352. ret = kstrtoint(buf, 10, &val);
  353. if (ret || (val < 0)) {
  354. pr_err("Incorrect available current threshold value\n");
  355. return -EINVAL;
  356. }
  357. gbcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] = val;
  358. return count;
  359. }
  360. /*
  361. * BCL device attributes
  362. */
  363. static struct device_attribute bcl_dev_attr[] = {
  364. __ATTR(type, 0444, type_show, NULL),
  365. __ATTR(iavail, 0444, iavail_show, NULL),
  366. __ATTR(vbat_min, 0644, vbat_min_show, vbat_min_store),
  367. __ATTR(vbat, 0444, vbat_show, NULL),
  368. __ATTR(rbat, 0444, rbat_show, NULL),
  369. __ATTR(mode, 0644, mode_show, mode_store),
  370. __ATTR(poll_interval, 0644,
  371. poll_interval_show, poll_interval_store),
  372. __ATTR(iavail_low_threshold_mode, 0644,
  373. iavail_low_threshold_mode_show,
  374. iavail_low_threshold_mode_store),
  375. __ATTR(iavail_high_threshold_mode, 0644,
  376. iavail_high_threshold_mode_show,
  377. iavail_high_threshold_mode_store),
  378. __ATTR(iavail_low_threshold_value, 0644,
  379. iavail_low_threshold_value_show,
  380. iavail_low_threshold_value_store),
  381. __ATTR(iavail_high_threshold_value, 0644,
  382. iavail_high_threshold_value_show,
  383. iavail_high_threshold_value_store),
  384. };
  385. static int create_bcl_sysfs(struct bcl_context *bcl)
  386. {
  387. int result = 0;
  388. int num_attr = sizeof(bcl_dev_attr)/sizeof(struct device_attribute);
  389. int i;
  390. for (i = 0; i < num_attr; i++) {
  391. result = device_create_file(bcl->dev, &bcl_dev_attr[i]);
  392. if (result < 0)
  393. return result;
  394. }
  395. return 0;
  396. }
  397. static void remove_bcl_sysfs(struct bcl_context *bcl)
  398. {
  399. int num_attr = sizeof(bcl_dev_attr)/sizeof(struct device_attribute);
  400. int i;
  401. for (i = 0; i < num_attr; i++)
  402. device_remove_file(bcl->dev, &bcl_dev_attr[i]);
  403. return;
  404. }
  405. static int __devinit bcl_probe(struct platform_device *pdev)
  406. {
  407. struct bcl_context *bcl;
  408. int ret = 0;
  409. bcl = kzalloc(sizeof(struct bcl_context), GFP_KERNEL);
  410. if (!bcl) {
  411. pr_err("Cannot allocate bcl_context\n");
  412. return -ENOMEM;
  413. }
  414. gbcl = bcl;
  415. /* For BCL */
  416. /* Init default BCL params */
  417. bcl->dev = &pdev->dev;
  418. bcl->bcl_mode = BCL_DEVICE_DISABLED;
  419. bcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE] =
  420. BCL_IAVAIL_THRESHOLD_DISABLED;
  421. bcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] =
  422. BCL_IAVAIL_THRESHOLD_DISABLED;
  423. bcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE] = 0;
  424. bcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] = 0;
  425. bcl->bcl_vbat_min = BATTERY_VOLTAGE_MIN;
  426. snprintf(bcl->bcl_type, BCL_NAME_LENGTH, "%s", bcl_type);
  427. bcl->bcl_poll_interval_msec = BCL_POLL_INTERVAL;
  428. ret = create_bcl_sysfs(bcl);
  429. if (ret < 0) {
  430. pr_err("Cannot create bcl sysfs\n");
  431. kfree(bcl);
  432. return ret;
  433. }
  434. platform_set_drvdata(pdev, bcl);
  435. INIT_DELAYED_WORK_DEFERRABLE(&bcl->bcl_iavail_work, bcl_iavail_work);
  436. return 0;
  437. }
  438. static int __devexit bcl_remove(struct platform_device *pdev)
  439. {
  440. remove_bcl_sysfs(gbcl);
  441. kfree(gbcl);
  442. gbcl = NULL;
  443. platform_set_drvdata(pdev, NULL);
  444. return 0;
  445. }
  446. static struct of_device_id bcl_match_table[] = {
  447. {.compatible = "qcom,bcl"},
  448. {},
  449. };
  450. static struct platform_driver bcl_driver = {
  451. .probe = bcl_probe,
  452. .remove = __devexit_p(bcl_remove),
  453. .driver = {
  454. .name = BCL_DEV_NAME,
  455. .owner = THIS_MODULE,
  456. .of_match_table = bcl_match_table,
  457. },
  458. };
  459. static int __init bcl_init(void)
  460. {
  461. return platform_driver_register(&bcl_driver);
  462. }
  463. static void __exit bcl_exit(void)
  464. {
  465. platform_driver_unregister(&bcl_driver);
  466. }
  467. late_initcall(bcl_init);
  468. module_exit(bcl_exit);
  469. MODULE_LICENSE("GPL v2");
  470. MODULE_DESCRIPTION("battery current limit driver");
  471. MODULE_ALIAS("platform:" BCL_DEV_NAME);