0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/device.h>
0012 #include <linux/kernel.h>
0013 #include <linux/platform_data/wilco-ec.h>
0014 #include <linux/string.h>
0015 #include <linux/sysfs.h>
0016 #include <linux/types.h>
0017
0018 #define CMD_KB_CMOS 0x7C
0019 #define SUB_CMD_KB_CMOS_AUTO_ON 0x03
0020
0021 struct boot_on_ac_request {
0022 u8 cmd;
0023 u8 reserved1;
0024 u8 sub_cmd;
0025 u8 reserved3to5[3];
0026 u8 val;
0027 u8 reserved7;
0028 } __packed;
0029
0030 #define CMD_USB_CHARGE 0x39
0031
0032 enum usb_charge_op {
0033 USB_CHARGE_GET = 0,
0034 USB_CHARGE_SET = 1,
0035 };
0036
0037 struct usb_charge_request {
0038 u8 cmd;
0039 u8 reserved;
0040 u8 op;
0041 u8 val;
0042 } __packed;
0043
0044 struct usb_charge_response {
0045 u8 reserved;
0046 u8 status;
0047 u8 val;
0048 } __packed;
0049
0050 #define CMD_EC_INFO 0x38
0051 enum get_ec_info_op {
0052 CMD_GET_EC_LABEL = 0,
0053 CMD_GET_EC_REV = 1,
0054 CMD_GET_EC_MODEL = 2,
0055 CMD_GET_EC_BUILD_DATE = 3,
0056 };
0057
0058 struct get_ec_info_req {
0059 u8 cmd;
0060 u8 reserved;
0061 u8 op;
0062 } __packed;
0063
0064 struct get_ec_info_resp {
0065 u8 reserved[2];
0066 char value[9];
0067 } __packed;
0068
0069 static ssize_t boot_on_ac_store(struct device *dev,
0070 struct device_attribute *attr,
0071 const char *buf, size_t count)
0072 {
0073 struct wilco_ec_device *ec = dev_get_drvdata(dev);
0074 struct boot_on_ac_request rq;
0075 struct wilco_ec_message msg;
0076 int ret;
0077 u8 val;
0078
0079 ret = kstrtou8(buf, 10, &val);
0080 if (ret < 0)
0081 return ret;
0082 if (val > 1)
0083 return -EINVAL;
0084
0085 memset(&rq, 0, sizeof(rq));
0086 rq.cmd = CMD_KB_CMOS;
0087 rq.sub_cmd = SUB_CMD_KB_CMOS_AUTO_ON;
0088 rq.val = val;
0089
0090 memset(&msg, 0, sizeof(msg));
0091 msg.type = WILCO_EC_MSG_LEGACY;
0092 msg.request_data = &rq;
0093 msg.request_size = sizeof(rq);
0094 ret = wilco_ec_mailbox(ec, &msg);
0095 if (ret < 0)
0096 return ret;
0097
0098 return count;
0099 }
0100
0101 static DEVICE_ATTR_WO(boot_on_ac);
0102
0103 static ssize_t get_info(struct device *dev, char *buf, enum get_ec_info_op op)
0104 {
0105 struct wilco_ec_device *ec = dev_get_drvdata(dev);
0106 struct get_ec_info_req req = { .cmd = CMD_EC_INFO, .op = op };
0107 struct get_ec_info_resp resp;
0108 int ret;
0109
0110 struct wilco_ec_message msg = {
0111 .type = WILCO_EC_MSG_LEGACY,
0112 .request_data = &req,
0113 .request_size = sizeof(req),
0114 .response_data = &resp,
0115 .response_size = sizeof(resp),
0116 };
0117
0118 ret = wilco_ec_mailbox(ec, &msg);
0119 if (ret < 0)
0120 return ret;
0121
0122 return scnprintf(buf, PAGE_SIZE, "%.*s\n", (int)sizeof(resp.value),
0123 (char *)&resp.value);
0124 }
0125
0126 static ssize_t version_show(struct device *dev, struct device_attribute *attr,
0127 char *buf)
0128 {
0129 return get_info(dev, buf, CMD_GET_EC_LABEL);
0130 }
0131
0132 static DEVICE_ATTR_RO(version);
0133
0134 static ssize_t build_revision_show(struct device *dev,
0135 struct device_attribute *attr, char *buf)
0136 {
0137 return get_info(dev, buf, CMD_GET_EC_REV);
0138 }
0139
0140 static DEVICE_ATTR_RO(build_revision);
0141
0142 static ssize_t build_date_show(struct device *dev,
0143 struct device_attribute *attr, char *buf)
0144 {
0145 return get_info(dev, buf, CMD_GET_EC_BUILD_DATE);
0146 }
0147
0148 static DEVICE_ATTR_RO(build_date);
0149
0150 static ssize_t model_number_show(struct device *dev,
0151 struct device_attribute *attr, char *buf)
0152 {
0153 return get_info(dev, buf, CMD_GET_EC_MODEL);
0154 }
0155
0156 static DEVICE_ATTR_RO(model_number);
0157
0158 static int send_usb_charge(struct wilco_ec_device *ec,
0159 struct usb_charge_request *rq,
0160 struct usb_charge_response *rs)
0161 {
0162 struct wilco_ec_message msg;
0163 int ret;
0164
0165 memset(&msg, 0, sizeof(msg));
0166 msg.type = WILCO_EC_MSG_LEGACY;
0167 msg.request_data = rq;
0168 msg.request_size = sizeof(*rq);
0169 msg.response_data = rs;
0170 msg.response_size = sizeof(*rs);
0171 ret = wilco_ec_mailbox(ec, &msg);
0172 if (ret < 0)
0173 return ret;
0174 if (rs->status)
0175 return -EIO;
0176
0177 return 0;
0178 }
0179
0180 static ssize_t usb_charge_show(struct device *dev,
0181 struct device_attribute *attr, char *buf)
0182 {
0183 struct wilco_ec_device *ec = dev_get_drvdata(dev);
0184 struct usb_charge_request rq;
0185 struct usb_charge_response rs;
0186 int ret;
0187
0188 memset(&rq, 0, sizeof(rq));
0189 rq.cmd = CMD_USB_CHARGE;
0190 rq.op = USB_CHARGE_GET;
0191
0192 ret = send_usb_charge(ec, &rq, &rs);
0193 if (ret < 0)
0194 return ret;
0195
0196 return sprintf(buf, "%d\n", rs.val);
0197 }
0198
0199 static ssize_t usb_charge_store(struct device *dev,
0200 struct device_attribute *attr,
0201 const char *buf, size_t count)
0202 {
0203 struct wilco_ec_device *ec = dev_get_drvdata(dev);
0204 struct usb_charge_request rq;
0205 struct usb_charge_response rs;
0206 int ret;
0207 u8 val;
0208
0209 ret = kstrtou8(buf, 10, &val);
0210 if (ret < 0)
0211 return ret;
0212 if (val > 1)
0213 return -EINVAL;
0214
0215 memset(&rq, 0, sizeof(rq));
0216 rq.cmd = CMD_USB_CHARGE;
0217 rq.op = USB_CHARGE_SET;
0218 rq.val = val;
0219
0220 ret = send_usb_charge(ec, &rq, &rs);
0221 if (ret < 0)
0222 return ret;
0223
0224 return count;
0225 }
0226
0227 static DEVICE_ATTR_RW(usb_charge);
0228
0229 static struct attribute *wilco_dev_attrs[] = {
0230 &dev_attr_boot_on_ac.attr,
0231 &dev_attr_build_date.attr,
0232 &dev_attr_build_revision.attr,
0233 &dev_attr_model_number.attr,
0234 &dev_attr_usb_charge.attr,
0235 &dev_attr_version.attr,
0236 NULL,
0237 };
0238
0239 static const struct attribute_group wilco_dev_attr_group = {
0240 .attrs = wilco_dev_attrs,
0241 };
0242
0243 int wilco_ec_add_sysfs(struct wilco_ec_device *ec)
0244 {
0245 return sysfs_create_group(&ec->dev->kobj, &wilco_dev_attr_group);
0246 }
0247
0248 void wilco_ec_remove_sysfs(struct wilco_ec_device *ec)
0249 {
0250 sysfs_remove_group(&ec->dev->kobj, &wilco_dev_attr_group);
0251 }