summaryrefslogtreecommitdiffstats
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 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 */
239static 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
249static void cros_ec_class_release(struct device *dev) 60static 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
455static const struct mfd_cell cros_ec_platform_cells[] = { 266static 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 = {
647static int __init cros_ec_dev_init(void) 451static 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
674failed_devreg: 469failed_devreg:
675 unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV);
676failed_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:
681static void __exit cros_ec_dev_exit(void) 474static 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 */
203struct cros_ec_dev { 202struct 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;