18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2019 Google LLC
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/errno.h>
78c2ecf20Sopenharmony_ci#include <linux/export.h>
88c2ecf20Sopenharmony_ci#include <linux/platform_data/wilco-ec.h>
98c2ecf20Sopenharmony_ci#include <linux/string.h>
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/* Operation code; what the EC should do with the property */
148c2ecf20Sopenharmony_cienum ec_property_op {
158c2ecf20Sopenharmony_ci	EC_OP_GET = 0,
168c2ecf20Sopenharmony_ci	EC_OP_SET = 1,
178c2ecf20Sopenharmony_ci};
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistruct ec_property_request {
208c2ecf20Sopenharmony_ci	u8 op; /* One of enum ec_property_op */
218c2ecf20Sopenharmony_ci	u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
228c2ecf20Sopenharmony_ci	u8 length;
238c2ecf20Sopenharmony_ci	u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
248c2ecf20Sopenharmony_ci} __packed;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct ec_property_response {
278c2ecf20Sopenharmony_ci	u8 reserved[2];
288c2ecf20Sopenharmony_ci	u8 op; /* One of enum ec_property_op */
298c2ecf20Sopenharmony_ci	u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
308c2ecf20Sopenharmony_ci	u8 length;
318c2ecf20Sopenharmony_ci	u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
328c2ecf20Sopenharmony_ci} __packed;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int send_property_msg(struct wilco_ec_device *ec,
358c2ecf20Sopenharmony_ci			     struct ec_property_request *rq,
368c2ecf20Sopenharmony_ci			     struct ec_property_response *rs)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct wilco_ec_message ec_msg;
398c2ecf20Sopenharmony_ci	int ret;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	memset(&ec_msg, 0, sizeof(ec_msg));
428c2ecf20Sopenharmony_ci	ec_msg.type = WILCO_EC_MSG_PROPERTY;
438c2ecf20Sopenharmony_ci	ec_msg.request_data = rq;
448c2ecf20Sopenharmony_ci	ec_msg.request_size = sizeof(*rq);
458c2ecf20Sopenharmony_ci	ec_msg.response_data = rs;
468c2ecf20Sopenharmony_ci	ec_msg.response_size = sizeof(*rs);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	ret = wilco_ec_mailbox(ec, &ec_msg);
498c2ecf20Sopenharmony_ci	if (ret < 0)
508c2ecf20Sopenharmony_ci		return ret;
518c2ecf20Sopenharmony_ci	if (rs->op != rq->op)
528c2ecf20Sopenharmony_ci		return -EBADMSG;
538c2ecf20Sopenharmony_ci	if (memcmp(rq->property_id, rs->property_id, sizeof(rs->property_id)))
548c2ecf20Sopenharmony_ci		return -EBADMSG;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return 0;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ciint wilco_ec_get_property(struct wilco_ec_device *ec,
608c2ecf20Sopenharmony_ci			  struct wilco_ec_property_msg *prop_msg)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct ec_property_request rq;
638c2ecf20Sopenharmony_ci	struct ec_property_response rs;
648c2ecf20Sopenharmony_ci	int ret;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	memset(&rq, 0, sizeof(rq));
678c2ecf20Sopenharmony_ci	rq.op = EC_OP_GET;
688c2ecf20Sopenharmony_ci	put_unaligned_le32(prop_msg->property_id, rq.property_id);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	ret = send_property_msg(ec, &rq, &rs);
718c2ecf20Sopenharmony_ci	if (ret < 0)
728c2ecf20Sopenharmony_ci		return ret;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	prop_msg->length = rs.length;
758c2ecf20Sopenharmony_ci	memcpy(prop_msg->data, rs.data, rs.length);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return 0;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wilco_ec_get_property);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ciint wilco_ec_set_property(struct wilco_ec_device *ec,
828c2ecf20Sopenharmony_ci			  struct wilco_ec_property_msg *prop_msg)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	struct ec_property_request rq;
858c2ecf20Sopenharmony_ci	struct ec_property_response rs;
868c2ecf20Sopenharmony_ci	int ret;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	memset(&rq, 0, sizeof(rq));
898c2ecf20Sopenharmony_ci	rq.op = EC_OP_SET;
908c2ecf20Sopenharmony_ci	put_unaligned_le32(prop_msg->property_id, rq.property_id);
918c2ecf20Sopenharmony_ci	rq.length = prop_msg->length;
928c2ecf20Sopenharmony_ci	memcpy(rq.data, prop_msg->data, prop_msg->length);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	ret = send_property_msg(ec, &rq, &rs);
958c2ecf20Sopenharmony_ci	if (ret < 0)
968c2ecf20Sopenharmony_ci		return ret;
978c2ecf20Sopenharmony_ci	if (rs.length != prop_msg->length)
988c2ecf20Sopenharmony_ci		return -EBADMSG;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wilco_ec_set_property);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ciint wilco_ec_get_byte_property(struct wilco_ec_device *ec, u32 property_id,
1058c2ecf20Sopenharmony_ci			       u8 *val)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct wilco_ec_property_msg msg;
1088c2ecf20Sopenharmony_ci	int ret;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	msg.property_id = property_id;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	ret = wilco_ec_get_property(ec, &msg);
1138c2ecf20Sopenharmony_ci	if (ret < 0)
1148c2ecf20Sopenharmony_ci		return ret;
1158c2ecf20Sopenharmony_ci	if (msg.length != 1)
1168c2ecf20Sopenharmony_ci		return -EBADMSG;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	*val = msg.data[0];
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return 0;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ciint wilco_ec_set_byte_property(struct wilco_ec_device *ec, u32 property_id,
1258c2ecf20Sopenharmony_ci			       u8 val)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct wilco_ec_property_msg msg;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	msg.property_id = property_id;
1308c2ecf20Sopenharmony_ci	msg.data[0] = val;
1318c2ecf20Sopenharmony_ci	msg.length = 1;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return wilco_ec_set_property(ec, &msg);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);
136