Linux-libre 5.7.3-gnu
[librecmc/linux-libre.git] / drivers / platform / chrome / wilco_ec / properties.c
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 */
14 enum ec_property_op {
15         EC_OP_GET = 0,
16         EC_OP_SET = 1,
17 };
18
19 struct 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
26 struct 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
34 static 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
59 int 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 }
79 EXPORT_SYMBOL_GPL(wilco_ec_get_property);
80
81 int 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 }
102 EXPORT_SYMBOL_GPL(wilco_ec_set_property);
103
104 int 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 }
122 EXPORT_SYMBOL_GPL(wilco_ec_get_byte_property);
123
124 int 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 }
135 EXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);