xref: /linux/drivers/platform/chrome/wilco_ec/properties.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
10c0b7ea2SNick Crews // SPDX-License-Identifier: GPL-2.0
20c0b7ea2SNick Crews /*
30c0b7ea2SNick Crews  * Copyright 2019 Google LLC
40c0b7ea2SNick Crews  */
50c0b7ea2SNick Crews 
6*8673e944SAndy Shevchenko #include <linux/errno.h>
7*8673e944SAndy Shevchenko #include <linux/export.h>
80c0b7ea2SNick Crews #include <linux/platform_data/wilco-ec.h>
90c0b7ea2SNick Crews #include <linux/string.h>
10*8673e944SAndy Shevchenko #include <linux/types.h>
110cbb4f9cSStephen Boyd #include <asm/unaligned.h>
120c0b7ea2SNick Crews 
130c0b7ea2SNick Crews /* Operation code; what the EC should do with the property */
140c0b7ea2SNick Crews enum ec_property_op {
150c0b7ea2SNick Crews 	EC_OP_GET = 0,
160c0b7ea2SNick Crews 	EC_OP_SET = 1,
170c0b7ea2SNick Crews };
180c0b7ea2SNick Crews 
190c0b7ea2SNick Crews struct ec_property_request {
200c0b7ea2SNick Crews 	u8 op; /* One of enum ec_property_op */
210c0b7ea2SNick Crews 	u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
220c0b7ea2SNick Crews 	u8 length;
230c0b7ea2SNick Crews 	u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
240c0b7ea2SNick Crews } __packed;
250c0b7ea2SNick Crews 
260c0b7ea2SNick Crews struct ec_property_response {
270c0b7ea2SNick Crews 	u8 reserved[2];
280c0b7ea2SNick Crews 	u8 op; /* One of enum ec_property_op */
290c0b7ea2SNick Crews 	u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
300c0b7ea2SNick Crews 	u8 length;
310c0b7ea2SNick Crews 	u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
320c0b7ea2SNick Crews } __packed;
330c0b7ea2SNick Crews 
send_property_msg(struct wilco_ec_device * ec,struct ec_property_request * rq,struct ec_property_response * rs)340c0b7ea2SNick Crews static int send_property_msg(struct wilco_ec_device *ec,
350c0b7ea2SNick Crews 			     struct ec_property_request *rq,
360c0b7ea2SNick Crews 			     struct ec_property_response *rs)
370c0b7ea2SNick Crews {
380c0b7ea2SNick Crews 	struct wilco_ec_message ec_msg;
390c0b7ea2SNick Crews 	int ret;
400c0b7ea2SNick Crews 
410c0b7ea2SNick Crews 	memset(&ec_msg, 0, sizeof(ec_msg));
420c0b7ea2SNick Crews 	ec_msg.type = WILCO_EC_MSG_PROPERTY;
430c0b7ea2SNick Crews 	ec_msg.request_data = rq;
440c0b7ea2SNick Crews 	ec_msg.request_size = sizeof(*rq);
450c0b7ea2SNick Crews 	ec_msg.response_data = rs;
460c0b7ea2SNick Crews 	ec_msg.response_size = sizeof(*rs);
470c0b7ea2SNick Crews 
480c0b7ea2SNick Crews 	ret = wilco_ec_mailbox(ec, &ec_msg);
490c0b7ea2SNick Crews 	if (ret < 0)
500c0b7ea2SNick Crews 		return ret;
510c0b7ea2SNick Crews 	if (rs->op != rq->op)
520c0b7ea2SNick Crews 		return -EBADMSG;
530c0b7ea2SNick Crews 	if (memcmp(rq->property_id, rs->property_id, sizeof(rs->property_id)))
540c0b7ea2SNick Crews 		return -EBADMSG;
550c0b7ea2SNick Crews 
560c0b7ea2SNick Crews 	return 0;
570c0b7ea2SNick Crews }
580c0b7ea2SNick Crews 
wilco_ec_get_property(struct wilco_ec_device * ec,struct wilco_ec_property_msg * prop_msg)590c0b7ea2SNick Crews int wilco_ec_get_property(struct wilco_ec_device *ec,
600c0b7ea2SNick Crews 			  struct wilco_ec_property_msg *prop_msg)
610c0b7ea2SNick Crews {
620c0b7ea2SNick Crews 	struct ec_property_request rq;
630c0b7ea2SNick Crews 	struct ec_property_response rs;
640c0b7ea2SNick Crews 	int ret;
650c0b7ea2SNick Crews 
660c0b7ea2SNick Crews 	memset(&rq, 0, sizeof(rq));
670c0b7ea2SNick Crews 	rq.op = EC_OP_GET;
680c0b7ea2SNick Crews 	put_unaligned_le32(prop_msg->property_id, rq.property_id);
690c0b7ea2SNick Crews 
700c0b7ea2SNick Crews 	ret = send_property_msg(ec, &rq, &rs);
710c0b7ea2SNick Crews 	if (ret < 0)
720c0b7ea2SNick Crews 		return ret;
730c0b7ea2SNick Crews 
740c0b7ea2SNick Crews 	prop_msg->length = rs.length;
750c0b7ea2SNick Crews 	memcpy(prop_msg->data, rs.data, rs.length);
760c0b7ea2SNick Crews 
770c0b7ea2SNick Crews 	return 0;
780c0b7ea2SNick Crews }
790c0b7ea2SNick Crews EXPORT_SYMBOL_GPL(wilco_ec_get_property);
800c0b7ea2SNick Crews 
wilco_ec_set_property(struct wilco_ec_device * ec,struct wilco_ec_property_msg * prop_msg)810c0b7ea2SNick Crews int wilco_ec_set_property(struct wilco_ec_device *ec,
820c0b7ea2SNick Crews 			  struct wilco_ec_property_msg *prop_msg)
830c0b7ea2SNick Crews {
840c0b7ea2SNick Crews 	struct ec_property_request rq;
850c0b7ea2SNick Crews 	struct ec_property_response rs;
860c0b7ea2SNick Crews 	int ret;
870c0b7ea2SNick Crews 
880c0b7ea2SNick Crews 	memset(&rq, 0, sizeof(rq));
890c0b7ea2SNick Crews 	rq.op = EC_OP_SET;
900c0b7ea2SNick Crews 	put_unaligned_le32(prop_msg->property_id, rq.property_id);
910c0b7ea2SNick Crews 	rq.length = prop_msg->length;
920c0b7ea2SNick Crews 	memcpy(rq.data, prop_msg->data, prop_msg->length);
930c0b7ea2SNick Crews 
940c0b7ea2SNick Crews 	ret = send_property_msg(ec, &rq, &rs);
950c0b7ea2SNick Crews 	if (ret < 0)
960c0b7ea2SNick Crews 		return ret;
970c0b7ea2SNick Crews 	if (rs.length != prop_msg->length)
980c0b7ea2SNick Crews 		return -EBADMSG;
990c0b7ea2SNick Crews 
1000c0b7ea2SNick Crews 	return 0;
1010c0b7ea2SNick Crews }
1020c0b7ea2SNick Crews EXPORT_SYMBOL_GPL(wilco_ec_set_property);
1030c0b7ea2SNick Crews 
wilco_ec_get_byte_property(struct wilco_ec_device * ec,u32 property_id,u8 * val)1040c0b7ea2SNick Crews int wilco_ec_get_byte_property(struct wilco_ec_device *ec, u32 property_id,
1050c0b7ea2SNick Crews 			       u8 *val)
1060c0b7ea2SNick Crews {
1070c0b7ea2SNick Crews 	struct wilco_ec_property_msg msg;
1080c0b7ea2SNick Crews 	int ret;
1090c0b7ea2SNick Crews 
1100c0b7ea2SNick Crews 	msg.property_id = property_id;
1110c0b7ea2SNick Crews 
1120c0b7ea2SNick Crews 	ret = wilco_ec_get_property(ec, &msg);
1130c0b7ea2SNick Crews 	if (ret < 0)
1140c0b7ea2SNick Crews 		return ret;
1150c0b7ea2SNick Crews 	if (msg.length != 1)
1160c0b7ea2SNick Crews 		return -EBADMSG;
1170c0b7ea2SNick Crews 
1180c0b7ea2SNick Crews 	*val = msg.data[0];
1190c0b7ea2SNick Crews 
1200c0b7ea2SNick Crews 	return 0;
1210c0b7ea2SNick Crews }
1220c0b7ea2SNick Crews EXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
1230c0b7ea2SNick Crews 
wilco_ec_set_byte_property(struct wilco_ec_device * ec,u32 property_id,u8 val)1240c0b7ea2SNick Crews int wilco_ec_set_byte_property(struct wilco_ec_device *ec, u32 property_id,
1250c0b7ea2SNick Crews 			       u8 val)
1260c0b7ea2SNick Crews {
1270c0b7ea2SNick Crews 	struct wilco_ec_property_msg msg;
1280c0b7ea2SNick Crews 
1290c0b7ea2SNick Crews 	msg.property_id = property_id;
1300c0b7ea2SNick Crews 	msg.data[0] = val;
1310c0b7ea2SNick Crews 	msg.length = 1;
1320c0b7ea2SNick Crews 
1330c0b7ea2SNick Crews 	return wilco_ec_set_property(ec, &msg);
1340c0b7ea2SNick Crews }
1350c0b7ea2SNick Crews EXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);
136