Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
Note: File does not exist in v4.6.
  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 */
 11enum ec_property_op {
 12	EC_OP_GET = 0,
 13	EC_OP_SET = 1,
 14};
 15
 16struct 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
 23struct 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
 31static 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
 56int 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}
 76EXPORT_SYMBOL_GPL(wilco_ec_get_property);
 77
 78int 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}
 99EXPORT_SYMBOL_GPL(wilco_ec_set_property);
100
101int 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}
119EXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
120
121int 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}
132EXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);