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 | case CROS_EC_DEV_IOCRDMEM: | ||
232 | return ec_device_ioctl_readmem(ec, (void __user *)arg); | ||
233 | } | ||
234 | |||
235 | return -ENOTTY; | ||
236 | } | ||
237 | |||
238 | /* Module initialization */ | ||
239 | static const struct file_operations fops = { | ||
240 | .open = ec_device_open, | ||
241 | .release = ec_device_release, | ||
242 | .read = ec_device_read, | ||
243 | .unlocked_ioctl = ec_device_ioctl, | ||
244 | #ifdef CONFIG_COMPAT | ||
245 | .compat_ioctl = ec_device_ioctl, | ||
246 | #endif | ||
247 | }; | ||
248 | |||
249 | static void cros_ec_class_release(struct device *dev) | 60 | static void cros_ec_class_release(struct device *dev) |
250 | { | 61 | { |
251 | kfree(to_cros_ec_dev(dev)); | 62 | kfree(to_cros_ec_dev(dev)); |
@@ -453,6 +264,7 @@ static const struct mfd_cell cros_usbpd_charger_cells[] = { | |||
453 | }; | 264 | }; |
454 | 265 | ||
455 | static const struct mfd_cell cros_ec_platform_cells[] = { | 266 | static const struct mfd_cell cros_ec_platform_cells[] = { |
267 | { .name = "cros-ec-chardev" }, | ||
456 | { .name = "cros-ec-debugfs" }, | 268 | { .name = "cros-ec-debugfs" }, |
457 | { .name = "cros-ec-lightbar" }, | 269 | { .name = "cros-ec-lightbar" }, |
458 | { .name = "cros-ec-sysfs" }, | 270 | { .name = "cros-ec-sysfs" }, |
@@ -480,7 +292,6 @@ static int ec_device_probe(struct platform_device *pdev) | |||
480 | ec->features[0] = -1U; /* Not cached yet */ | 292 | ec->features[0] = -1U; /* Not cached yet */ |
481 | ec->features[1] = -1U; /* Not cached yet */ | 293 | ec->features[1] = -1U; /* Not cached yet */ |
482 | device_initialize(&ec->class_dev); | 294 | device_initialize(&ec->class_dev); |
483 | cdev_init(&ec->cdev, &fops); | ||
484 | 295 | ||
485 | /* Check whether this is actually a Fingerprint MCU rather than an EC */ | 296 | /* Check whether this is actually a Fingerprint MCU rather than an EC */ |
486 | if (cros_ec_check_features(ec, EC_FEATURE_FINGERPRINT)) { | 297 | if (cros_ec_check_features(ec, EC_FEATURE_FINGERPRINT)) { |
@@ -527,10 +338,7 @@ static int ec_device_probe(struct platform_device *pdev) | |||
527 | 338 | ||
528 | /* | 339 | /* |
529 | * Add the class device | 340 | * Add the class device |
530 | * Link to the character device for creating the /dev entry | ||
531 | * in devtmpfs. | ||
532 | */ | 341 | */ |
533 | ec->class_dev.devt = MKDEV(ec_major, pdev->id); | ||
534 | ec->class_dev.class = &cros_class; | 342 | ec->class_dev.class = &cros_class; |
535 | ec->class_dev.parent = dev; | 343 | ec->class_dev.parent = dev; |
536 | ec->class_dev.release = cros_ec_class_release; | 344 | ec->class_dev.release = cros_ec_class_release; |
@@ -541,6 +349,10 @@ static int ec_device_probe(struct platform_device *pdev) | |||
541 | goto failed; | 349 | goto failed; |
542 | } | 350 | } |
543 | 351 | ||
352 | retval = device_add(&ec->class_dev); | ||
353 | if (retval) | ||
354 | goto failed; | ||
355 | |||
544 | /* check whether this EC is a sensor hub. */ | 356 | /* check whether this EC is a sensor hub. */ |
545 | if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) | 357 | if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) |
546 | cros_ec_sensors_register(ec); | 358 | cros_ec_sensors_register(ec); |
@@ -584,13 +396,6 @@ static int ec_device_probe(struct platform_device *pdev) | |||
584 | retval); | 396 | retval); |
585 | } | 397 | } |
586 | 398 | ||
587 | /* We can now add the sysfs class, we know which parameter to show */ | ||
588 | retval = cdev_device_add(&ec->cdev, &ec->class_dev); | ||
589 | if (retval) { | ||
590 | dev_err(dev, "cdev_device_add failed => %d\n", retval); | ||
591 | goto failed; | ||
592 | } | ||
593 | |||
594 | retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, | 399 | retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, |
595 | cros_ec_platform_cells, | 400 | cros_ec_platform_cells, |
596 | ARRAY_SIZE(cros_ec_platform_cells), | 401 | ARRAY_SIZE(cros_ec_platform_cells), |
@@ -624,7 +429,6 @@ static int ec_device_remove(struct platform_device *pdev) | |||
624 | struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); | 429 | struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); |
625 | 430 | ||
626 | mfd_remove_devices(ec->dev); | 431 | mfd_remove_devices(ec->dev); |
627 | cdev_del(&ec->cdev); | ||
628 | device_unregister(&ec->class_dev); | 432 | device_unregister(&ec->class_dev); |
629 | return 0; | 433 | return 0; |
630 | } | 434 | } |
@@ -647,7 +451,6 @@ static struct platform_driver cros_ec_dev_driver = { | |||
647 | static int __init cros_ec_dev_init(void) | 451 | static int __init cros_ec_dev_init(void) |
648 | { | 452 | { |
649 | int ret; | 453 | int ret; |
650 | dev_t dev = 0; | ||
651 | 454 | ||
652 | ret = class_register(&cros_class); | 455 | ret = class_register(&cros_class); |
653 | if (ret) { | 456 | if (ret) { |
@@ -655,14 +458,6 @@ static int __init cros_ec_dev_init(void) | |||
655 | return ret; | 458 | return ret; |
656 | } | 459 | } |
657 | 460 | ||
658 | /* Get a range of minor numbers (starting with 0) to work with */ | ||
659 | ret = alloc_chrdev_region(&dev, 0, CROS_MAX_DEV, CROS_EC_DEV_NAME); | ||
660 | if (ret < 0) { | ||
661 | pr_err(CROS_EC_DEV_NAME ": alloc_chrdev_region() failed\n"); | ||
662 | goto failed_chrdevreg; | ||
663 | } | ||
664 | ec_major = MAJOR(dev); | ||
665 | |||
666 | /* Register the driver */ | 461 | /* Register the driver */ |
667 | ret = platform_driver_register(&cros_ec_dev_driver); | 462 | ret = platform_driver_register(&cros_ec_dev_driver); |
668 | if (ret < 0) { | 463 | if (ret < 0) { |
@@ -672,8 +467,6 @@ static int __init cros_ec_dev_init(void) | |||
672 | return 0; | 467 | return 0; |
673 | 468 | ||
674 | failed_devreg: | 469 | failed_devreg: |
675 | unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV); | ||
676 | failed_chrdevreg: | ||
677 | class_unregister(&cros_class); | 470 | class_unregister(&cros_class); |
678 | return ret; | 471 | return ret; |
679 | } | 472 | } |
@@ -681,7 +474,6 @@ failed_chrdevreg: | |||
681 | static void __exit cros_ec_dev_exit(void) | 474 | static void __exit cros_ec_dev_exit(void) |
682 | { | 475 | { |
683 | platform_driver_unregister(&cros_ec_dev_driver); | 476 | platform_driver_unregister(&cros_ec_dev_driver); |
684 | unregister_chrdev(ec_major, CROS_EC_DEV_NAME); | ||
685 | class_unregister(&cros_class); | 477 | class_unregister(&cros_class); |
686 | } | 478 | } |
687 | 479 | ||
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h index bcccda0257ff..569428ad1cb1 100644 --- a/include/linux/mfd/cros_ec.h +++ b/include/linux/mfd/cros_ec.h | |||
@@ -192,7 +192,6 @@ struct cros_ec_debugfs; | |||
192 | /** | 192 | /** |
193 | * struct cros_ec_dev - ChromeOS EC device entry point. | 193 | * struct cros_ec_dev - ChromeOS EC device entry point. |
194 | * @class_dev: Device structure used in sysfs. | 194 | * @class_dev: Device structure used in sysfs. |
195 | * @cdev: Character device structure in /dev. | ||
196 | * @ec_dev: cros_ec_device structure to talk to the physical device. | 195 | * @ec_dev: cros_ec_device structure to talk to the physical device. |
197 | * @dev: Pointer to the platform device. | 196 | * @dev: Pointer to the platform device. |
198 | * @debug_info: cros_ec_debugfs structure for debugging information. | 197 | * @debug_info: cros_ec_debugfs structure for debugging information. |
@@ -202,7 +201,6 @@ struct cros_ec_debugfs; | |||
202 | */ | 201 | */ |
203 | struct cros_ec_dev { | 202 | struct cros_ec_dev { |
204 | struct device class_dev; | 203 | struct device class_dev; |
205 | struct cdev cdev; | ||
206 | struct cros_ec_device *ec_dev; | 204 | struct cros_ec_device *ec_dev; |
207 | struct device *dev; | 205 | struct device *dev; |
208 | struct cros_ec_debugfs *debug_info; | 206 | struct cros_ec_debugfs *debug_info; |