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