properties.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2019 Google LLC
  4. */
  5. #include <linux/errno.h>
  6. #include <linux/export.h>
  7. #include <linux/platform_data/wilco-ec.h>
  8. #include <linux/string.h>
  9. #include <linux/types.h>
  10. #include <linux/unaligned.h>
  11. /* Operation code; what the EC should do with the property */
  12. enum ec_property_op {
  13. EC_OP_GET = 0,
  14. EC_OP_SET = 1,
  15. };
  16. struct ec_property_request {
  17. u8 op; /* One of enum ec_property_op */
  18. u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
  19. u8 length;
  20. u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
  21. } __packed;
  22. struct ec_property_response {
  23. u8 reserved[2];
  24. u8 op; /* One of enum ec_property_op */
  25. u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
  26. u8 length;
  27. u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
  28. } __packed;
  29. static int send_property_msg(struct wilco_ec_device *ec,
  30. struct ec_property_request *rq,
  31. struct ec_property_response *rs)
  32. {
  33. struct wilco_ec_message ec_msg;
  34. int ret;
  35. memset(&ec_msg, 0, sizeof(ec_msg));
  36. ec_msg.type = WILCO_EC_MSG_PROPERTY;
  37. ec_msg.request_data = rq;
  38. ec_msg.request_size = sizeof(*rq);
  39. ec_msg.response_data = rs;
  40. ec_msg.response_size = sizeof(*rs);
  41. ret = wilco_ec_mailbox(ec, &ec_msg);
  42. if (ret < 0)
  43. return ret;
  44. if (rs->op != rq->op)
  45. return -EBADMSG;
  46. if (memcmp(rq->property_id, rs->property_id, sizeof(rs->property_id)))
  47. return -EBADMSG;
  48. return 0;
  49. }
  50. int wilco_ec_get_property(struct wilco_ec_device *ec,
  51. struct wilco_ec_property_msg *prop_msg)
  52. {
  53. struct ec_property_request rq;
  54. struct ec_property_response rs;
  55. int ret;
  56. memset(&rq, 0, sizeof(rq));
  57. rq.op = EC_OP_GET;
  58. put_unaligned_le32(prop_msg->property_id, rq.property_id);
  59. ret = send_property_msg(ec, &rq, &rs);
  60. if (ret < 0)
  61. return ret;
  62. prop_msg->length = rs.length;
  63. memcpy(prop_msg->data, rs.data, rs.length);
  64. return 0;
  65. }
  66. EXPORT_SYMBOL_GPL(wilco_ec_get_property);
  67. int wilco_ec_set_property(struct wilco_ec_device *ec,
  68. struct wilco_ec_property_msg *prop_msg)
  69. {
  70. struct ec_property_request rq;
  71. struct ec_property_response rs;
  72. int ret;
  73. memset(&rq, 0, sizeof(rq));
  74. rq.op = EC_OP_SET;
  75. put_unaligned_le32(prop_msg->property_id, rq.property_id);
  76. rq.length = prop_msg->length;
  77. memcpy(rq.data, prop_msg->data, prop_msg->length);
  78. ret = send_property_msg(ec, &rq, &rs);
  79. if (ret < 0)
  80. return ret;
  81. if (rs.length != prop_msg->length)
  82. return -EBADMSG;
  83. return 0;
  84. }
  85. EXPORT_SYMBOL_GPL(wilco_ec_set_property);
  86. int wilco_ec_get_byte_property(struct wilco_ec_device *ec, u32 property_id,
  87. u8 *val)
  88. {
  89. struct wilco_ec_property_msg msg;
  90. int ret;
  91. msg.property_id = property_id;
  92. ret = wilco_ec_get_property(ec, &msg);
  93. if (ret < 0)
  94. return ret;
  95. if (msg.length != 1)
  96. return -EBADMSG;
  97. *val = msg.data[0];
  98. return 0;
  99. }
  100. EXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
  101. int wilco_ec_set_byte_property(struct wilco_ec_device *ec, u32 property_id,
  102. u8 val)
  103. {
  104. struct wilco_ec_property_msg msg;
  105. msg.property_id = property_id;
  106. msg.data[0] = val;
  107. msg.length = 1;
  108. return wilco_ec_set_property(ec, &msg);
  109. }
  110. EXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);