Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright 2019 Google LLC
0004  *
0005  * Sysfs properties to view and modify EC-controlled features on Wilco devices.
0006  * The entries will appear under /sys/bus/platform/devices/GOOG000C:00/
0007  *
0008  * See Documentation/ABI/testing/sysfs-platform-wilco-ec for more information.
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;         /* Always CMD_KB_CMOS */
0023     u8 reserved1;
0024     u8 sub_cmd;     /* Always SUB_CMD_KB_CMOS_AUTO_ON */
0025     u8 reserved3to5[3];
0026     u8 val;         /* Either 0 or 1 */
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;     /* Always CMD_USB_CHARGE */
0039     u8 reserved;
0040     u8 op;      /* One of enum usb_charge_op */
0041     u8 val;     /* When setting, either 0 or 1 */
0042 } __packed;
0043 
0044 struct usb_charge_response {
0045     u8 reserved;
0046     u8 status;  /* Set by EC to 0 on success, other value on failure */
0047     u8 val;     /* When getting, set by EC to either 0 or 1 */
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;         /* Always CMD_EC_INFO */
0060     u8 reserved;
0061     u8 op;          /* One of enum get_ec_info_op */
0062 } __packed;
0063 
0064 struct get_ec_info_resp {
0065     u8 reserved[2];
0066     char value[9]; /* __nonstring: might not be null terminated */
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 }