diff options
| author | Enric Balletbo i Serra <enric.balletbo@collabora.com> | 2019-09-02 05:53:03 -0400 |
|---|---|---|
| committer | Lee Jones <lee.jones@linaro.org> | 2019-09-02 06:33:27 -0400 |
| commit | 459aedb9a5d4b92e4aee343ee8ee5aeca8e1d93a (patch) | |
| tree | a281ebec665528506d8a1f21baccc5535f8e9c0a | |
| parent | eda2e30c6684d67288edb841c6125d48c608a242 (diff) | |
mfd: cros_ec: Switch to use the new cros-ec-chardev driver
With the purpose of remove the things that far extends the bounds of
what a MFD was designed to do, instantiate the new platform misc
cros-ec-chardev driver and get rid of all the unneeded code. After this
patch the misc chardev driver is a sub-device of the MFD, and all the
new file operations should be implemented there.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
Tested-by: Gwendal Grignou <gwendal@chromium.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
| -rw-r--r-- | drivers/mfd/cros_ec_dev.c | 220 | ||||
| -rw-r--r-- | include/linux/mfd/cros_ec.h | 2 |
2 files changed, 6 insertions, 216 deletions
diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 4c96445b1bf5..0c1c0ce3453e 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c | |||
| @@ -5,76 +5,23 @@ | |||
| 5 | * Copyright (C) 2014 Google, Inc. | 5 | * Copyright (C) 2014 Google, Inc. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/fs.h> | ||
| 9 | #include <linux/mfd/core.h> | 8 | #include <linux/mfd/core.h> |
| 10 | #include <linux/mfd/cros_ec.h> | 9 | #include <linux/mfd/cros_ec.h> |
| 11 | #include <linux/mfd/cros_ec_commands.h> | 10 | #include <linux/mfd/cros_ec_commands.h> |
| 12 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 13 | #include <linux/mod_devicetable.h> | 12 | #include <linux/mod_devicetable.h> |
| 14 | #include <linux/platform_data/cros_ec_chardev.h> | ||
| 15 | #include <linux/of_platform.h> | 13 | #include <linux/of_platform.h> |
| 16 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
| 17 | #include <linux/pm.h> | 15 | #include <linux/platform_data/cros_ec_chardev.h> |
| 18 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 19 | #include <linux/uaccess.h> | ||
| 20 | |||
| 21 | 17 | ||
| 22 | #define DRV_NAME "cros-ec-dev" | 18 | #define DRV_NAME "cros-ec-dev" |
| 23 | 19 | ||
| 24 | /* Device variables */ | ||
| 25 | #define CROS_MAX_DEV 128 | ||
| 26 | static int ec_major; | ||
| 27 | |||
| 28 | static struct class cros_class = { | 20 | static struct class cros_class = { |
| 29 | .owner = THIS_MODULE, | 21 | .owner = THIS_MODULE, |
| 30 | .name = "chromeos", | 22 | .name = "chromeos", |
| 31 | }; | 23 | }; |
| 32 | 24 | ||
| 33 | /* Basic communication */ | ||
| 34 | static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen) | ||
| 35 | { | ||
| 36 | struct ec_response_get_version *resp; | ||
| 37 | static const char * const current_image_name[] = { | ||
| 38 | "unknown", "read-only", "read-write", "invalid", | ||
| 39 | }; | ||
| 40 | struct cros_ec_command *msg; | ||
| 41 | int ret; | ||
| 42 | |||
| 43 | msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); | ||
| 44 | if (!msg) | ||
| 45 | return -ENOMEM; | ||
| 46 | |||
| 47 | msg->version = 0; | ||
| 48 | msg->command = EC_CMD_GET_VERSION + ec->cmd_offset; | ||
| 49 | msg->insize = sizeof(*resp); | ||
| 50 | msg->outsize = 0; | ||
| 51 | |||
| 52 | ret = cros_ec_cmd_xfer(ec->ec_dev, msg); | ||
| 53 | if (ret < 0) | ||
| 54 | goto exit; | ||
| 55 | |||
| 56 | if (msg->result != EC_RES_SUCCESS) { | ||
| 57 | snprintf(str, maxlen, | ||
| 58 | "%s\nUnknown EC version: EC returned %d\n", | ||
| 59 | CROS_EC_DEV_VERSION, msg->result); | ||
| 60 | ret = -EINVAL; | ||
| 61 | goto exit; | ||
| 62 | } | ||
| 63 | |||
| 64 | resp = (struct ec_response_get_version *)msg->data; | ||
| 65 | if (resp->current_image >= ARRAY_SIZE(current_image_name)) | ||
| 66 | resp->current_image = 3; /* invalid */ | ||
| 67 | |||
| 68 | snprintf(str, maxlen, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION, | ||
| 69 | resp->version_string_ro, resp->version_string_rw, | ||
| 70 | current_image_name[resp->current_image]); | ||
| 71 | |||
| 72 | ret = 0; | ||
| 73 | exit: | ||
| 74 | kfree(msg); | ||
| 75 | return ret; | ||
| 76 | } | ||
| 77 | |||
| 78 | static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) | 25 | static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) |
| 79 | { | 26 | { |
| 80 | struct cros_ec_command *msg; | 27 | struct cros_ec_command *msg; |
| @@ -110,142 +57,6 @@ static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) | |||
| 110 | return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature); | 57 | return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature); |
| 111 | } | 58 | } |
| 112 | 59 | ||
| 113 | /* Device file ops */ | ||
| 114 | static int ec_device_open(struct inode *inode, struct file *filp) | ||
| 115 | { | ||
| 116 | struct cros_ec_dev *ec = container_of(inode->i_cdev, | ||
| 117 | struct cros_ec_dev, cdev); | ||
| 118 | filp->private_data = ec; | ||
| 119 | nonseekable_open(inode, filp); | ||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | static int ec_device_release(struct inode *inode, struct file *filp) | ||
| 124 | { | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | static ssize_t ec_device_read(struct file *filp, char __user *buffer, | ||
| 129 | size_t length, loff_t *offset) | ||
| 130 | { | ||
| 131 | struct cros_ec_dev *ec = filp->private_data; | ||
| 132 | char msg[sizeof(struct ec_response_get_version) + | ||
| 133 | sizeof(CROS_EC_DEV_VERSION)]; | ||
| 134 | size_t count; | ||
| 135 | int ret; | ||
| 136 | |||
| 137 | if (*offset != 0) | ||
| 138 | return 0; | ||
| 139 | |||
| 140 | ret = ec_get_version(ec, msg, sizeof(msg)); | ||
| 141 | if (ret) | ||
| 142 | return ret; | ||
| 143 | |||
| 144 | count = min(length, strlen(msg)); | ||
| 145 | |||
| 146 | if (copy_to_user(buffer, msg, count)) | ||
| 147 | return -EFAULT; | ||
| 148 | |||
| 149 | *offset = count; | ||
| 150 | return count; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* Ioctls */ | ||
| 154 | static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) | ||
| 155 | { | ||
| 156 | long ret; | ||
| 157 | struct cros_ec_command u_cmd; | ||
| 158 | struct cros_ec_command *s_cmd; | ||
| 159 | |||
| 160 | if (copy_from_user(&u_cmd, arg, sizeof(u_cmd))) | ||
| 161 | return -EFAULT; | ||
| 162 | |||
| 163 | if ((u_cmd.outsize > EC_MAX_MSG_BYTES) || | ||
| 164 | (u_cmd.insize > EC_MAX_MSG_BYTES)) | ||
| 165 | return -EINVAL; | ||
| 166 | |||
| 167 | s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize), | ||
| 168 | GFP_KERNEL); | ||
| 169 | if (!s_cmd) | ||
| 170 | return -ENOMEM; | ||
| 171 | |||
| 172 | if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) { | ||
| 173 | ret = -EFAULT; | ||
| 174 | goto exit; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (u_cmd.outsize != s_cmd->outsize || | ||
| 178 | u_cmd.insize != s_cmd->insize) { | ||
| 179 | ret = -EINVAL; | ||
| 180 | goto exit; | ||
| 181 | } | ||
| 182 | |||
| 183 | s_cmd->command += ec->cmd_offset; | ||
| 184 | ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd); | ||
| 185 | /* Only copy data to userland if data was received. */ | ||
| 186 | if (ret < 0) | ||
| 187 | goto exit; | ||
| 188 | |||
| 189 | if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize)) | ||
| 190 | ret = -EFAULT; | ||
| 191 | exit: | ||
| 192 | kfree(s_cmd); | ||
| 193 | return ret; | ||
| 194 | } | ||
| 195 | |||
| 196 | static long ec_device_ioctl_readmem(struct cros_ec_dev *ec, void __user *arg) | ||
| 197 | { | ||
| 198 | struct cros_ec_device *ec_dev = ec->ec_dev; | ||
| 199 | struct cros_ec_readmem s_mem = { }; | ||
| 200 | long num; | ||
| 201 | |||
| 202 | /* Not every platform supports direct reads */ | ||
| 203 | if (!ec_dev->cmd_readmem) | ||
| 204 | return -ENOTTY; | ||
| 205 | |||
| 206 | if (copy_from_user(&s_mem, arg, sizeof(s_mem))) | ||
| 207 | return -EFAULT; | ||
| 208 | |||
| 209 | num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes, | ||
| 210 | s_mem.buffer); | ||
| 211 | if (num <= 0) | ||
| 212 | return num; | ||
| 213 | |||
| 214 | if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem))) | ||
| 215 | return -EFAULT; | ||
| 216 | |||
| 217 | return num; | ||
| 218 | } | ||
| 219 | |||
| 220 | static long ec_device_ioctl(struct file *filp, unsigned int cmd, | ||
| 221 | unsigned long arg) | ||
| 222 | { | ||
| 223 | struct cros_ec_dev *ec = filp->private_data; | ||
| 224 | |||
| 225 | if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC) | ||
| 226 | return -ENOTTY; | ||
| 227 | |||
| 228 | switch (cmd) { | ||
| 229 | case CROS_EC_DEV_IOCXCMD: | ||
| 230 | return ec_device_ioctl_xcmd(ec, (void __user *)arg); | ||
| 231 | |||
