sb_wireless.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * sb_wireless.c
  3. * Samsung Mobile Battery Wireless Module
  4. *
  5. * Copyright (C) 2023 Samsung Electronics
  6. *
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/of.h>
  13. #include <linux/slab.h>
  14. #include <linux/device.h>
  15. #include <linux/module.h>
  16. #include <linux/battery/sb_sysfs.h>
  17. #include <linux/battery/sb_notify.h>
  18. #include <linux/battery/sb_wireless.h>
  19. #define sbw_log(str, ...) pr_info("[SB-WIRELESS]:%s: "str, __func__, ##__VA_ARGS__)
  20. #define SBW_MODULE_NAME "sb-wireless"
  21. const char *sb_wrl_op_mode_str(int op_mode)
  22. {
  23. switch (op_mode) {
  24. case WPC_OP_MODE_PPDE:
  25. return "PPDE";
  26. case WPC_OP_MODE_EPP:
  27. return "EPP";
  28. case WPC_OP_MODE_MPP:
  29. return "MPP";
  30. case WPC_OP_MODE_BPP:
  31. return "BPP";
  32. }
  33. return "Unknown";
  34. }
  35. EXPORT_SYMBOL(sb_wrl_op_mode_str);
  36. struct sb_wireless {
  37. struct notifier_block nb;
  38. const struct sb_wireless_op *op;
  39. void *pdata;
  40. };
  41. static struct sb_wireless *get_inst(void)
  42. {
  43. static struct sb_wireless *sbw;
  44. if (sbw)
  45. return sbw;
  46. sbw = kzalloc(sizeof(struct sb_wireless), GFP_KERNEL);
  47. return sbw;
  48. }
  49. static bool check_valid_op(const struct sb_wireless_op *op)
  50. {
  51. return (op != NULL) &&
  52. (op->get_op_mode != NULL) &&
  53. (op->get_qi_ver != NULL) &&
  54. (op->get_auth_mode != NULL);
  55. }
  56. static int get_op_mode(void)
  57. {
  58. struct sb_wireless *sbw = get_inst();
  59. if (!sbw)
  60. return -ENOMEM;
  61. if (!check_valid_op(sbw->op))
  62. return -ENODEV;
  63. return sbw->op->get_op_mode(sbw->pdata);
  64. }
  65. static int get_qi_ver(void)
  66. {
  67. struct sb_wireless *sbw = get_inst();
  68. if (!sbw)
  69. return -ENOMEM;
  70. if (!check_valid_op(sbw->op))
  71. return -ENODEV;
  72. return sbw->op->get_qi_ver(sbw->pdata);
  73. }
  74. static int get_auth_mode(void)
  75. {
  76. struct sb_wireless *sbw = get_inst();
  77. if (!sbw)
  78. return -ENOMEM;
  79. if (!check_valid_op(sbw->op))
  80. return -ENODEV;
  81. return sbw->op->get_auth_mode(sbw->pdata);
  82. }
  83. int sb_wireless_set_op(void *pdata, const struct sb_wireless_op *op)
  84. {
  85. struct sb_wireless *sbw = get_inst();
  86. if (!sbw)
  87. return -ENOMEM;
  88. if (check_valid_op(sbw->op))
  89. return -EBUSY;
  90. if (!pdata || !check_valid_op(op))
  91. return -EINVAL;
  92. sbw->pdata = pdata;
  93. sbw->op = op;
  94. return 0;
  95. }
  96. EXPORT_SYMBOL(sb_wireless_set_op);
  97. static ssize_t
  98. sb_wireless_show_attrs(struct device *, struct device_attribute *, char *);
  99. static ssize_t
  100. sb_wireless_store_attrs(struct device *, struct device_attribute *, const char *, size_t);
  101. #define SB_WIRELESS_ATTR(_name) \
  102. { \
  103. .attr = {.name = #_name, .mode = 0664}, \
  104. .show = sb_wireless_show_attrs, \
  105. .store = sb_wireless_store_attrs, \
  106. }
  107. enum {
  108. WPC_OP_MODE = 0,
  109. WPC_QI_VER,
  110. WPC_AUTH_MODE,
  111. };
  112. static struct device_attribute sb_wireless_attrs[] = {
  113. SB_WIRELESS_ATTR(wpc_op_mode),
  114. SB_WIRELESS_ATTR(wpc_qi_ver),
  115. SB_WIRELESS_ATTR(wpc_auth_mode),
  116. };
  117. static ssize_t sb_wireless_show_attrs(struct device *dev,
  118. struct device_attribute *attr, char *buf)
  119. {
  120. const ptrdiff_t offset = attr - sb_wireless_attrs;
  121. int i = 0;
  122. switch (offset) {
  123. case WPC_OP_MODE:
  124. i += scnprintf(buf, PAGE_SIZE, "%d\n", get_op_mode());
  125. break;
  126. case WPC_QI_VER:
  127. i += scnprintf(buf, PAGE_SIZE, "%d\n", get_qi_ver());
  128. break;
  129. case WPC_AUTH_MODE:
  130. i += scnprintf(buf, PAGE_SIZE, "%d\n", get_auth_mode());
  131. break;
  132. default:
  133. return -EINVAL;
  134. }
  135. return i;
  136. }
  137. static ssize_t sb_wireless_store_attrs(struct device *dev,
  138. struct device_attribute *attr,
  139. const char *buf, size_t count)
  140. {
  141. const ptrdiff_t offset = attr - sb_wireless_attrs;
  142. switch (offset) {
  143. case WPC_OP_MODE:
  144. break;
  145. case WPC_QI_VER:
  146. break;
  147. case WPC_AUTH_MODE:
  148. break;
  149. default:
  150. return -EINVAL;
  151. }
  152. return count;
  153. }
  154. static int sb_noti_handler(struct notifier_block *nb, unsigned long action, void *data)
  155. {
  156. return 0;
  157. }
  158. static int __init sb_wireless_init(void)
  159. {
  160. struct sb_wireless *sbw = get_inst();
  161. int ret = 0;
  162. if (!sbw)
  163. return -ENOMEM;
  164. ret = sb_sysfs_add_attrs(SBW_MODULE_NAME, sbw, sb_wireless_attrs, ARRAY_SIZE(sb_wireless_attrs));
  165. sbw_log("sb_sysfs_add_attrs ret = %s\n", (ret) ? "fail" : "success");
  166. ret = sb_notify_register(&sbw->nb, sb_noti_handler, SBW_MODULE_NAME, SB_DEV_MODULE);
  167. sbw_log("sb_notify_register ret = %s\n", (ret) ? "fail" : "success");
  168. return ret;
  169. }
  170. module_init(sb_wireless_init);
  171. MODULE_DESCRIPTION("Samsung Battery Wireless");
  172. MODULE_AUTHOR("Samsung Electronics");
  173. MODULE_LICENSE("GPL");