Linux Audio

Check our new training course

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/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 */
 14enum ec_property_op {
 15	EC_OP_GET = 0,
 16	EC_OP_SET = 1,
 17};
 18
 19struct 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
 26struct 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
 34static 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
 59int 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}
 79EXPORT_SYMBOL_GPL(wilco_ec_get_property);
 80
 81int 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}
102EXPORT_SYMBOL_GPL(wilco_ec_set_property);
103
104int 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}
122EXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
123
124int 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}
135EXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);