aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEnric Balletbo i Serra <enric.balletbo@collabora.com>2019-09-02 05:53:03 -0400
committerLee Jones <lee.jones@linaro.org>2019-09-02 06:33:27 -0400
commit459aedb9a5d4b92e4aee343ee8ee5aeca8e1d93a (patch)
treea281ebec665528506d8a1f21baccc5535f8e9c0a
parenteda2e30c6684d67288edb841c6125d48c608a242 (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.c220
-rw-r--r--include/linux/mfd/cros_ec.h2
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
26static int ec_major;
27
28static struct class cros_class = { 20static 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 */
34static 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;
73exit:
74 kfree(msg);
75 return ret;
76}
77
78static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) 25static 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 */
114static 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
123static int ec_device_release(struct inode *inode, struct file *filp)
124{
125 return 0;
126}
127
128static 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 */
154static 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;
191exit:
192 kfree(s_cmd);
193 return ret;
194}
195
196static 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
220static 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