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