1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2019 Google LLC 4 * 5 * Sysfs properties to view and modify EC-controlled features on Wilco devices. 6 * The entries will appear under /sys/bus/platform/devices/GOOG000C:00/ 7 * 8 * See Documentation/ABI/testing/sysfs-platform-wilco-ec for more information. 9 */ 10 11 #include <linux/platform_data/wilco-ec.h> 12 #include <linux/sysfs.h> 13 14 #define CMD_KB_CMOS 0x7C 15 #define SUB_CMD_KB_CMOS_AUTO_ON 0x03 16 17 struct boot_on_ac_request { 18 u8 cmd; /* Always CMD_KB_CMOS */ 19 u8 reserved1; 20 u8 sub_cmd; /* Always SUB_CMD_KB_CMOS_AUTO_ON */ 21 u8 reserved3to5[3]; 22 u8 val; /* Either 0 or 1 */ 23 u8 reserved7; 24 } __packed; 25 26 #define CMD_EC_INFO 0x38 27 enum get_ec_info_op { 28 CMD_GET_EC_LABEL = 0, 29 CMD_GET_EC_REV = 1, 30 CMD_GET_EC_MODEL = 2, 31 CMD_GET_EC_BUILD_DATE = 3, 32 }; 33 34 struct get_ec_info_req { 35 u8 cmd; /* Always CMD_EC_INFO */ 36 u8 reserved; 37 u8 op; /* One of enum get_ec_info_op */ 38 } __packed; 39 40 struct get_ec_info_resp { 41 u8 reserved[2]; 42 char value[9]; /* __nonstring: might not be null terminated */ 43 } __packed; 44 45 static ssize_t boot_on_ac_store(struct device *dev, 46 struct device_attribute *attr, 47 const char *buf, size_t count) 48 { 49 struct wilco_ec_device *ec = dev_get_drvdata(dev); 50 struct boot_on_ac_request rq; 51 struct wilco_ec_message msg; 52 int ret; 53 u8 val; 54 55 ret = kstrtou8(buf, 10, &val); 56 if (ret < 0) 57 return ret; 58 if (val > 1) 59 return -EINVAL; 60 61 memset(&rq, 0, sizeof(rq)); 62 rq.cmd = CMD_KB_CMOS; 63 rq.sub_cmd = SUB_CMD_KB_CMOS_AUTO_ON; 64 rq.val = val; 65 66 memset(&msg, 0, sizeof(msg)); 67 msg.type = WILCO_EC_MSG_LEGACY; 68 msg.request_data = &rq; 69 msg.request_size = sizeof(rq); 70 ret = wilco_ec_mailbox(ec, &msg); 71 if (ret < 0) 72 return ret; 73 74 return count; 75 } 76 77 static DEVICE_ATTR_WO(boot_on_ac); 78 79 static ssize_t get_info(struct device *dev, char *buf, enum get_ec_info_op op) 80 { 81 struct wilco_ec_device *ec = dev_get_drvdata(dev); 82 struct get_ec_info_req req = { .cmd = CMD_EC_INFO, .op = op }; 83 struct get_ec_info_resp resp; 84 int ret; 85 86 struct wilco_ec_message msg = { 87 .type = WILCO_EC_MSG_LEGACY, 88 .request_data = &req, 89 .request_size = sizeof(req), 90 .response_data = &resp, 91 .response_size = sizeof(resp), 92 }; 93 94 ret = wilco_ec_mailbox(ec, &msg); 95 if (ret < 0) 96 return ret; 97 98 return scnprintf(buf, PAGE_SIZE, "%.*s\n", (int)sizeof(resp.value), 99 (char *)&resp.value); 100 } 101 102 static ssize_t version_show(struct device *dev, struct device_attribute *attr, 103 char *buf) 104 { 105 return get_info(dev, buf, CMD_GET_EC_LABEL); 106 } 107 108 static DEVICE_ATTR_RO(version); 109 110 static ssize_t build_revision_show(struct device *dev, 111 struct device_attribute *attr, char *buf) 112 { 113 return get_info(dev, buf, CMD_GET_EC_REV); 114 } 115 116 static DEVICE_ATTR_RO(build_revision); 117 118 static ssize_t build_date_show(struct device *dev, 119 struct device_attribute *attr, char *buf) 120 { 121 return get_info(dev, buf, CMD_GET_EC_BUILD_DATE); 122 } 123 124 static DEVICE_ATTR_RO(build_date); 125 126 static ssize_t model_number_show(struct device *dev, 127 struct device_attribute *attr, char *buf) 128 { 129 return get_info(dev, buf, CMD_GET_EC_MODEL); 130 } 131 132 static DEVICE_ATTR_RO(model_number); 133 134 135 static struct attribute *wilco_dev_attrs[] = { 136 &dev_attr_boot_on_ac.attr, 137 &dev_attr_build_date.attr, 138 &dev_attr_build_revision.attr, 139 &dev_attr_model_number.attr, 140 &dev_attr_version.attr, 141 NULL, 142 }; 143 144 static struct attribute_group wilco_dev_attr_group = { 145 .attrs = wilco_dev_attrs, 146 }; 147 148 int wilco_ec_add_sysfs(struct wilco_ec_device *ec) 149 { 150 return sysfs_create_group(&ec->dev->kobj, &wilco_dev_attr_group); 151 } 152 153 void wilco_ec_remove_sysfs(struct wilco_ec_device *ec) 154 { 155 sysfs_remove_group(&ec->dev->kobj, &wilco_dev_attr_group); 156 } 157