forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.0 KiB
135 lines
3.0 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* |
|
* Copyright 2019 Google LLC |
|
*/ |
|
|
|
#include <linux/errno.h> |
|
#include <linux/export.h> |
|
#include <linux/platform_data/wilco-ec.h> |
|
#include <linux/string.h> |
|
#include <linux/types.h> |
|
#include <asm/unaligned.h> |
|
|
|
/* Operation code; what the EC should do with the property */ |
|
enum ec_property_op { |
|
EC_OP_GET = 0, |
|
EC_OP_SET = 1, |
|
}; |
|
|
|
struct ec_property_request { |
|
u8 op; /* One of enum ec_property_op */ |
|
u8 property_id[4]; /* The 32 bit PID is stored Little Endian */ |
|
u8 length; |
|
u8 data[WILCO_EC_PROPERTY_MAX_SIZE]; |
|
} __packed; |
|
|
|
struct ec_property_response { |
|
u8 reserved[2]; |
|
u8 op; /* One of enum ec_property_op */ |
|
u8 property_id[4]; /* The 32 bit PID is stored Little Endian */ |
|
u8 length; |
|
u8 data[WILCO_EC_PROPERTY_MAX_SIZE]; |
|
} __packed; |
|
|
|
static int send_property_msg(struct wilco_ec_device *ec, |
|
struct ec_property_request *rq, |
|
struct ec_property_response *rs) |
|
{ |
|
struct wilco_ec_message ec_msg; |
|
int ret; |
|
|
|
memset(&ec_msg, 0, sizeof(ec_msg)); |
|
ec_msg.type = WILCO_EC_MSG_PROPERTY; |
|
ec_msg.request_data = rq; |
|
ec_msg.request_size = sizeof(*rq); |
|
ec_msg.response_data = rs; |
|
ec_msg.response_size = sizeof(*rs); |
|
|
|
ret = wilco_ec_mailbox(ec, &ec_msg); |
|
if (ret < 0) |
|
return ret; |
|
if (rs->op != rq->op) |
|
return -EBADMSG; |
|
if (memcmp(rq->property_id, rs->property_id, sizeof(rs->property_id))) |
|
return -EBADMSG; |
|
|
|
return 0; |
|
} |
|
|
|
int wilco_ec_get_property(struct wilco_ec_device *ec, |
|
struct wilco_ec_property_msg *prop_msg) |
|
{ |
|
struct ec_property_request rq; |
|
struct ec_property_response rs; |
|
int ret; |
|
|
|
memset(&rq, 0, sizeof(rq)); |
|
rq.op = EC_OP_GET; |
|
put_unaligned_le32(prop_msg->property_id, rq.property_id); |
|
|
|
ret = send_property_msg(ec, &rq, &rs); |
|
if (ret < 0) |
|
return ret; |
|
|
|
prop_msg->length = rs.length; |
|
memcpy(prop_msg->data, rs.data, rs.length); |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL_GPL(wilco_ec_get_property); |
|
|
|
int wilco_ec_set_property(struct wilco_ec_device *ec, |
|
struct wilco_ec_property_msg *prop_msg) |
|
{ |
|
struct ec_property_request rq; |
|
struct ec_property_response rs; |
|
int ret; |
|
|
|
memset(&rq, 0, sizeof(rq)); |
|
rq.op = EC_OP_SET; |
|
put_unaligned_le32(prop_msg->property_id, rq.property_id); |
|
rq.length = prop_msg->length; |
|
memcpy(rq.data, prop_msg->data, prop_msg->length); |
|
|
|
ret = send_property_msg(ec, &rq, &rs); |
|
if (ret < 0) |
|
return ret; |
|
if (rs.length != prop_msg->length) |
|
return -EBADMSG; |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL_GPL(wilco_ec_set_property); |
|
|
|
int wilco_ec_get_byte_property(struct wilco_ec_device *ec, u32 property_id, |
|
u8 *val) |
|
{ |
|
struct wilco_ec_property_msg msg; |
|
int ret; |
|
|
|
msg.property_id = property_id; |
|
|
|
ret = wilco_ec_get_property(ec, &msg); |
|
if (ret < 0) |
|
return ret; |
|
if (msg.length != 1) |
|
return -EBADMSG; |
|
|
|
*val = msg.data[0]; |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL_GPL(wilco_ec_get_byte_property); |
|
|
|
int wilco_ec_set_byte_property(struct wilco_ec_device *ec, u32 property_id, |
|
u8 val) |
|
{ |
|
struct wilco_ec_property_msg msg; |
|
|
|
msg.property_id = property_id; |
|
msg.data[0] = val; |
|
msg.length = 1; |
|
|
|
return wilco_ec_set_property(ec, &msg); |
|
} |
|
EXPORT_SYMBOL_GPL(wilco_ec_set_byte_property);
|
|
|