1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright 2019 Google LLC
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/errno.h>
7*4882a593Smuzhiyun #include <linux/export.h>
8*4882a593Smuzhiyun #include <linux/platform_data/wilco-ec.h>
9*4882a593Smuzhiyun #include <linux/string.h>
10*4882a593Smuzhiyun #include <linux/types.h>
11*4882a593Smuzhiyun #include <asm/unaligned.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /* Operation code; what the EC should do with the property */
14*4882a593Smuzhiyun enum ec_property_op {
15*4882a593Smuzhiyun EC_OP_GET = 0,
16*4882a593Smuzhiyun EC_OP_SET = 1,
17*4882a593Smuzhiyun };
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun struct ec_property_request {
20*4882a593Smuzhiyun u8 op; /* One of enum ec_property_op */
21*4882a593Smuzhiyun u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
22*4882a593Smuzhiyun u8 length;
23*4882a593Smuzhiyun u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
24*4882a593Smuzhiyun } __packed;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun struct ec_property_response {
27*4882a593Smuzhiyun u8 reserved[2];
28*4882a593Smuzhiyun u8 op; /* One of enum ec_property_op */
29*4882a593Smuzhiyun u8 property_id[4]; /* The 32 bit PID is stored Little Endian */
30*4882a593Smuzhiyun u8 length;
31*4882a593Smuzhiyun u8 data[WILCO_EC_PROPERTY_MAX_SIZE];
32*4882a593Smuzhiyun } __packed;
33*4882a593Smuzhiyun
send_property_msg(struct wilco_ec_device * ec,struct ec_property_request * rq,struct ec_property_response * rs)34*4882a593Smuzhiyun static int send_property_msg(struct wilco_ec_device *ec,
35*4882a593Smuzhiyun struct ec_property_request *rq,
36*4882a593Smuzhiyun struct ec_property_response *rs)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun struct wilco_ec_message ec_msg;
39*4882a593Smuzhiyun int ret;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun memset(&ec_msg, 0, sizeof(ec_msg));
42*4882a593Smuzhiyun ec_msg.type = WILCO_EC_MSG_PROPERTY;
43*4882a593Smuzhiyun ec_msg.request_data = rq;
44*4882a593Smuzhiyun ec_msg.request_size = sizeof(*rq);
45*4882a593Smuzhiyun ec_msg.response_data = rs;
46*4882a593Smuzhiyun ec_msg.response_size = sizeof(*rs);
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun ret = wilco_ec_mailbox(ec, &ec_msg);
49*4882a593Smuzhiyun if (ret < 0)
50*4882a593Smuzhiyun return ret;
51*4882a593Smuzhiyun if (rs->op != rq->op)
52*4882a593Smuzhiyun return -EBADMSG;
53*4882a593Smuzhiyun if (memcmp(rq->property_id, rs->property_id, sizeof(rs->property_id)))
54*4882a593Smuzhiyun return -EBADMSG;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun return 0;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
wilco_ec_get_property(struct wilco_ec_device * ec,struct wilco_ec_property_msg * prop_msg)59*4882a593Smuzhiyun int wilco_ec_get_property(struct wilco_ec_device *ec,
60*4882a593Smuzhiyun struct wilco_ec_property_msg *prop_msg)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun struct ec_property_request rq;
63*4882a593Smuzhiyun struct ec_property_response rs;
64*4882a593Smuzhiyun int ret;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun memset(&rq, 0, sizeof(rq));
67*4882a593Smuzhiyun rq.op = EC_OP_GET;
68*4882a593Smuzhiyun put_unaligned_le32(prop_msg->property_id, rq.property_id);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun ret = send_property_msg(ec, &rq, &rs);
71*4882a593Smuzhiyun if (ret < 0)
72*4882a593Smuzhiyun return ret;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun prop_msg->length = rs.length;
75*4882a593Smuzhiyun memcpy(prop_msg->data, rs.data, rs.length);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun return 0;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wilco_ec_get_property);
80*4882a593Smuzhiyun
wilco_ec_set_property(struct wilco_ec_device * ec,struct wilco_ec_property_msg * prop_msg)81*4882a593Smuzhiyun int wilco_ec_set_property(struct wilco_ec_device *ec,
82*4882a593Smuzhiyun struct wilco_ec_property_msg *prop_msg)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun struct ec_property_request rq;
85*4882a593Smuzhiyun struct ec_property_response rs;
86*4882a593Smuzhiyun int ret;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun memset(&rq, 0, sizeof(rq));
89*4882a593Smuzhiyun rq.op = EC_OP_SET;
90*4882a593Smuzhiyun put_unaligned_le32(prop_msg->property_id, rq.property_id);
91*4882a593Smuzhiyun rq.length = prop_msg->length;
92*4882a593Smuzhiyun memcpy(rq.data, prop_msg->data, prop_msg->length);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun ret = send_property_msg(ec, &rq, &rs);
95*4882a593Smuzhiyun if (ret < 0)
96*4882a593Smuzhiyun return ret;
97*4882a593Smuzhiyun if (rs.length != prop_msg->length)
98*4882a593Smuzhiyun return -EBADMSG;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wilco_ec_set_property);
103*4882a593Smuzhiyun
wilco_ec_get_byte_property(struct wilco_ec_device * ec,u32 property_id,u8 * val)104*4882a593Smuzhiyun int wilco_ec_get_byte_property(struct wilco_ec_device *ec, u32 property_id,
105*4882a593Smuzhiyun u8 *val)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun struct wilco_ec_property_msg msg;
108*4882a593Smuzhiyun int ret;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun msg.property_id = property_id;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun ret = wilco_ec_get_property(ec, &msg);
113*4882a593Smuzhiyun if (ret < 0)
114*4882a593Smuzhiyun return ret;
115*4882a593Smuzhiyun if (msg.length != 1)
116*4882a593Smuzhiyun return -EBADMSG;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun *val = msg.data[0];
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return 0;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
123*4882a593Smuzhiyun
wilco_ec_set_byte_property(struct wilco_ec_device * ec,u32 property_id,u8 val)124*4882a593Smuzhiyun int wilco_ec_set_byte_property(struct wilco_ec_device *ec, u32 property_id,
125*4882a593Smuzhiyun u8 val)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun struct wilco_ec_property_msg msg;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun msg.property_id = property_id;
130*4882a593Smuzhiyun msg.data[0] = val;
131*4882a593Smuzhiyun msg.length = 1;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun return wilco_ec_set_property(ec, &msg);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);
136