162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2019 Google LLC
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/errno.h>
762306a36Sopenharmony_ci#include <linux/export.h>
862306a36Sopenharmony_ci#include <linux/platform_data/wilco-ec.h>
962306a36Sopenharmony_ci#include <linux/string.h>
1062306a36Sopenharmony_ci#include <linux/types.h>
1162306a36Sopenharmony_ci#include <asm/unaligned.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/* Operation code; what the EC should do with the property */
1462306a36Sopenharmony_cienum ec_property_op {
1562306a36Sopenharmony_ci	EC_OP_GET = 0,
1662306a36Sopenharmony_ci	EC_OP_SET = 1,
1762306a36Sopenharmony_ci};
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistruct ec_property_request {
2062306a36Sopenharmony_ci	u8 op; /* One of enum ec_property_op */
2162306a36Sopenharmony_ci	u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
2262306a36Sopenharmony_ci	u8 length;
2362306a36Sopenharmony_ci	u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
2462306a36Sopenharmony_ci} __packed;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistruct ec_property_response {
2762306a36Sopenharmony_ci	u8 reserved[2];
2862306a36Sopenharmony_ci	u8 op; /* One of enum ec_property_op */
2962306a36Sopenharmony_ci	u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
3062306a36Sopenharmony_ci	u8 length;
3162306a36Sopenharmony_ci	u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
3262306a36Sopenharmony_ci} __packed;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int send_property_msg(struct wilco_ec_device *ec,
3562306a36Sopenharmony_ci			     struct ec_property_request *rq,
3662306a36Sopenharmony_ci			     struct ec_property_response *rs)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct wilco_ec_message ec_msg;
3962306a36Sopenharmony_ci	int ret;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	memset(&ec_msg, 0, sizeof(ec_msg));
4262306a36Sopenharmony_ci	ec_msg.type = WILCO_EC_MSG_PROPERTY;
4362306a36Sopenharmony_ci	ec_msg.request_data = rq;
4462306a36Sopenharmony_ci	ec_msg.request_size = sizeof(*rq);
4562306a36Sopenharmony_ci	ec_msg.response_data = rs;
4662306a36Sopenharmony_ci	ec_msg.response_size = sizeof(*rs);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	ret = wilco_ec_mailbox(ec, &ec_msg);
4962306a36Sopenharmony_ci	if (ret < 0)
5062306a36Sopenharmony_ci		return ret;
5162306a36Sopenharmony_ci	if (rs->op != rq->op)
5262306a36Sopenharmony_ci		return -EBADMSG;
5362306a36Sopenharmony_ci	if (memcmp(rq->property_id, rs->property_id, sizeof(rs->property_id)))
5462306a36Sopenharmony_ci		return -EBADMSG;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return 0;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciint wilco_ec_get_property(struct wilco_ec_device *ec,
6062306a36Sopenharmony_ci			  struct wilco_ec_property_msg *prop_msg)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct ec_property_request rq;
6362306a36Sopenharmony_ci	struct ec_property_response rs;
6462306a36Sopenharmony_ci	int ret;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	memset(&rq, 0, sizeof(rq));
6762306a36Sopenharmony_ci	rq.op = EC_OP_GET;
6862306a36Sopenharmony_ci	put_unaligned_le32(prop_msg->property_id, rq.property_id);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	ret = send_property_msg(ec, &rq, &rs);
7162306a36Sopenharmony_ci	if (ret < 0)
7262306a36Sopenharmony_ci		return ret;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	prop_msg->length = rs.length;
7562306a36Sopenharmony_ci	memcpy(prop_msg->data, rs.data, rs.length);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return 0;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(wilco_ec_get_property);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciint wilco_ec_set_property(struct wilco_ec_device *ec,
8262306a36Sopenharmony_ci			  struct wilco_ec_property_msg *prop_msg)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct ec_property_request rq;
8562306a36Sopenharmony_ci	struct ec_property_response rs;
8662306a36Sopenharmony_ci	int ret;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	memset(&rq, 0, sizeof(rq));
8962306a36Sopenharmony_ci	rq.op = EC_OP_SET;
9062306a36Sopenharmony_ci	put_unaligned_le32(prop_msg->property_id, rq.property_id);
9162306a36Sopenharmony_ci	rq.length = prop_msg->length;
9262306a36Sopenharmony_ci	memcpy(rq.data, prop_msg->data, prop_msg->length);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	ret = send_property_msg(ec, &rq, &rs);
9562306a36Sopenharmony_ci	if (ret < 0)
9662306a36Sopenharmony_ci		return ret;
9762306a36Sopenharmony_ci	if (rs.length != prop_msg->length)
9862306a36Sopenharmony_ci		return -EBADMSG;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(wilco_ec_set_property);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciint wilco_ec_get_byte_property(struct wilco_ec_device *ec, u32 property_id,
10562306a36Sopenharmony_ci			       u8 *val)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct wilco_ec_property_msg msg;
10862306a36Sopenharmony_ci	int ret;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	msg.property_id = property_id;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	ret = wilco_ec_get_property(ec, &msg);
11362306a36Sopenharmony_ci	if (ret < 0)
11462306a36Sopenharmony_ci		return ret;
11562306a36Sopenharmony_ci	if (msg.length != 1)
11662306a36Sopenharmony_ci		return -EBADMSG;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	*val = msg.data[0];
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciint wilco_ec_set_byte_property(struct wilco_ec_device *ec, u32 property_id,
12562306a36Sopenharmony_ci			       u8 val)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct wilco_ec_property_msg msg;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	msg.property_id = property_id;
13062306a36Sopenharmony_ci	msg.data[0] = val;
13162306a36Sopenharmony_ci	msg.length = 1;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return wilco_ec_set_property(ec, &msg);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);
136