2 * cros_ec_dev - expose the Chrome OS Embedded Controller to user-space
4 * Copyright (C) 2014 Google, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <linux/mfd/core.h>
22 #include <linux/module.h>
23 #include <linux/mod_devicetable.h>
24 #include <linux/platform_device.h>
26 #include <linux/slab.h>
27 #include <linux/uaccess.h>
29 #include "cros_ec_dev.h"
31 #define DRV_NAME "cros-ec-dev"
33 /* Device variables */
34 #define CROS_MAX_DEV 128
37 static const struct attribute_group
*cros_ec_groups
[] = {
39 &cros_ec_lightbar_attr_group
,
40 &cros_ec_vbc_attr_group
,
44 static struct class cros_class
= {
47 .dev_groups
= cros_ec_groups
,
50 /* Basic communication */
51 static int ec_get_version(struct cros_ec_dev
*ec
, char *str
, int maxlen
)
53 struct ec_response_get_version
*resp
;
54 static const char * const current_image_name
[] = {
55 "unknown", "read-only", "read-write", "invalid",
57 struct cros_ec_command
*msg
;
60 msg
= kmalloc(sizeof(*msg
) + sizeof(*resp
), GFP_KERNEL
);
65 msg
->command
= EC_CMD_GET_VERSION
+ ec
->cmd_offset
;
66 msg
->insize
= sizeof(*resp
);
69 ret
= cros_ec_cmd_xfer(ec
->ec_dev
, msg
);
73 if (msg
->result
!= EC_RES_SUCCESS
) {
75 "%s\nUnknown EC version: EC returned %d\n",
76 CROS_EC_DEV_VERSION
, msg
->result
);
81 resp
= (struct ec_response_get_version
*)msg
->data
;
82 if (resp
->current_image
>= ARRAY_SIZE(current_image_name
))
83 resp
->current_image
= 3; /* invalid */
85 snprintf(str
, maxlen
, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION
,
86 resp
->version_string_ro
, resp
->version_string_rw
,
87 current_image_name
[resp
->current_image
]);
95 static int cros_ec_check_features(struct cros_ec_dev
*ec
, int feature
)
97 struct cros_ec_command
*msg
;
100 if (ec
->features
[0] == -1U && ec
->features
[1] == -1U) {
101 /* features bitmap not read yet */
103 msg
= kmalloc(sizeof(*msg
) + sizeof(ec
->features
), GFP_KERNEL
);
108 msg
->command
= EC_CMD_GET_FEATURES
+ ec
->cmd_offset
;
109 msg
->insize
= sizeof(ec
->features
);
112 ret
= cros_ec_cmd_xfer(ec
->ec_dev
, msg
);
113 if (ret
< 0 || msg
->result
!= EC_RES_SUCCESS
) {
114 dev_warn(ec
->dev
, "cannot get EC features: %d/%d\n",
116 memset(ec
->features
, 0, sizeof(ec
->features
));
118 memcpy(ec
->features
, msg
->data
, sizeof(ec
->features
));
121 dev_dbg(ec
->dev
, "EC features %08x %08x\n",
122 ec
->features
[0], ec
->features
[1]);
127 return ec
->features
[feature
/ 32] & EC_FEATURE_MASK_0(feature
);
130 /* Device file ops */
131 static int ec_device_open(struct inode
*inode
, struct file
*filp
)
133 struct cros_ec_dev
*ec
= container_of(inode
->i_cdev
,
134 struct cros_ec_dev
, cdev
);
135 filp
->private_data
= ec
;
136 nonseekable_open(inode
, filp
);
140 static int ec_device_release(struct inode
*inode
, struct file
*filp
)
145 static ssize_t
ec_device_read(struct file
*filp
, char __user
*buffer
,
146 size_t length
, loff_t
*offset
)
148 struct cros_ec_dev
*ec
= filp
->private_data
;
149 char msg
[sizeof(struct ec_response_get_version
) +
150 sizeof(CROS_EC_DEV_VERSION
)];
157 ret
= ec_get_version(ec
, msg
, sizeof(msg
));
161 count
= min(length
, strlen(msg
));
163 if (copy_to_user(buffer
, msg
, count
))
171 static long ec_device_ioctl_xcmd(struct cros_ec_dev
*ec
, void __user
*arg
)
174 struct cros_ec_command u_cmd
;
175 struct cros_ec_command
*s_cmd
;
177 if (copy_from_user(&u_cmd
, arg
, sizeof(u_cmd
)))
180 if ((u_cmd
.outsize
> EC_MAX_MSG_BYTES
) ||
181 (u_cmd
.insize
> EC_MAX_MSG_BYTES
))
184 s_cmd
= kmalloc(sizeof(*s_cmd
) + max(u_cmd
.outsize
, u_cmd
.insize
),
189 if (copy_from_user(s_cmd
, arg
, sizeof(*s_cmd
) + u_cmd
.outsize
)) {
194 if (u_cmd
.outsize
!= s_cmd
->outsize
||
195 u_cmd
.insize
!= s_cmd
->insize
) {
200 s_cmd
->command
+= ec
->cmd_offset
;
201 ret
= cros_ec_cmd_xfer(ec
->ec_dev
, s_cmd
);
202 /* Only copy data to userland if data was received. */
206 if (copy_to_user(arg
, s_cmd
, sizeof(*s_cmd
) + s_cmd
->insize
))
213 static long ec_device_ioctl_readmem(struct cros_ec_dev
*ec
, void __user
*arg
)
215 struct cros_ec_device
*ec_dev
= ec
->ec_dev
;
216 struct cros_ec_readmem s_mem
= { };
219 /* Not every platform supports direct reads */
220 if (!ec_dev
->cmd_readmem
)
223 if (copy_from_user(&s_mem
, arg
, sizeof(s_mem
)))
226 num
= ec_dev
->cmd_readmem(ec_dev
, s_mem
.offset
, s_mem
.bytes
,
231 if (copy_to_user((void __user
*)arg
, &s_mem
, sizeof(s_mem
)))
237 static long ec_device_ioctl(struct file
*filp
, unsigned int cmd
,
240 struct cros_ec_dev
*ec
= filp
->private_data
;
242 if (_IOC_TYPE(cmd
) != CROS_EC_DEV_IOC
)
246 case CROS_EC_DEV_IOCXCMD
:
247 return ec_device_ioctl_xcmd(ec
, (void __user
*)arg
);
248 case CROS_EC_DEV_IOCRDMEM
:
249 return ec_device_ioctl_readmem(ec
, (void __user
*)arg
);
255 /* Module initialization */
256 static const struct file_operations fops
= {
257 .open
= ec_device_open
,
258 .release
= ec_device_release
,
259 .read
= ec_device_read
,
260 .unlocked_ioctl
= ec_device_ioctl
,
262 .compat_ioctl
= ec_device_ioctl
,
266 static void cros_ec_class_release(struct device
*dev
)
268 kfree(to_cros_ec_dev(dev
));
271 static void cros_ec_sensors_register(struct cros_ec_dev
*ec
)
274 * Issue a command to get the number of sensor reported.
275 * Build an array of sensors driver and register them all.
277 int ret
, i
, id
, sensor_num
;
278 struct mfd_cell
*sensor_cells
;
279 struct cros_ec_sensor_platform
*sensor_platforms
;
280 int sensor_type
[MOTIONSENSE_TYPE_MAX
];
281 struct ec_params_motion_sense
*params
;
282 struct ec_response_motion_sense
*resp
;
283 struct cros_ec_command
*msg
;
285 msg
= kzalloc(sizeof(struct cros_ec_command
) +
286 max(sizeof(*params
), sizeof(*resp
)), GFP_KERNEL
);
291 msg
->command
= EC_CMD_MOTION_SENSE_CMD
+ ec
->cmd_offset
;
292 msg
->outsize
= sizeof(*params
);
293 msg
->insize
= sizeof(*resp
);
295 params
= (struct ec_params_motion_sense
*)msg
->data
;
296 params
->cmd
= MOTIONSENSE_CMD_DUMP
;
298 ret
= cros_ec_cmd_xfer(ec
->ec_dev
, msg
);
299 if (ret
< 0 || msg
->result
!= EC_RES_SUCCESS
) {
300 dev_warn(ec
->dev
, "cannot get EC sensor information: %d/%d\n",
305 resp
= (struct ec_response_motion_sense
*)msg
->data
;
306 sensor_num
= resp
->dump
.sensor_count
;
307 /* Allocate 1 extra sensors in FIFO are needed */
308 sensor_cells
= kcalloc(sensor_num
+ 1, sizeof(struct mfd_cell
),
310 if (sensor_cells
== NULL
)
313 sensor_platforms
= kcalloc(sensor_num
+ 1,
314 sizeof(struct cros_ec_sensor_platform
),
316 if (sensor_platforms
== NULL
)
317 goto error_platforms
;
319 memset(sensor_type
, 0, sizeof(sensor_type
));
321 for (i
= 0; i
< sensor_num
; i
++) {
322 params
->cmd
= MOTIONSENSE_CMD_INFO
;
323 params
->info
.sensor_num
= i
;
324 ret
= cros_ec_cmd_xfer(ec
->ec_dev
, msg
);
325 if (ret
< 0 || msg
->result
!= EC_RES_SUCCESS
) {
326 dev_warn(ec
->dev
, "no info for EC sensor %d : %d/%d\n",
327 i
, ret
, msg
->result
);
330 switch (resp
->info
.type
) {
331 case MOTIONSENSE_TYPE_ACCEL
:
332 sensor_cells
[id
].name
= "cros-ec-accel";
334 case MOTIONSENSE_TYPE_BARO
:
335 sensor_cells
[id
].name
= "cros-ec-baro";
337 case MOTIONSENSE_TYPE_GYRO
:
338 sensor_cells
[id
].name
= "cros-ec-gyro";
340 case MOTIONSENSE_TYPE_MAG
:
341 sensor_cells
[id
].name
= "cros-ec-mag";
343 case MOTIONSENSE_TYPE_PROX
:
344 sensor_cells
[id
].name
= "cros-ec-prox";
346 case MOTIONSENSE_TYPE_LIGHT
:
347 sensor_cells
[id
].name
= "cros-ec-light";
349 case MOTIONSENSE_TYPE_ACTIVITY
:
350 sensor_cells
[id
].name
= "cros-ec-activity";
353 dev_warn(ec
->dev
, "unknown type %d\n", resp
->info
.type
);
356 sensor_platforms
[id
].sensor_num
= i
;
357 sensor_cells
[id
].id
= sensor_type
[resp
->info
.type
];
358 sensor_cells
[id
].platform_data
= &sensor_platforms
[id
];
359 sensor_cells
[id
].pdata_size
=
360 sizeof(struct cros_ec_sensor_platform
);
362 sensor_type
[resp
->info
.type
]++;
366 if (sensor_type
[MOTIONSENSE_TYPE_ACCEL
] >= 2)
367 ec
->has_kb_wake_angle
= true;
369 if (cros_ec_check_features(ec
, EC_FEATURE_MOTION_SENSE_FIFO
)) {
370 sensor_cells
[id
].name
= "cros-ec-ring";
374 ret
= mfd_add_devices(ec
->dev
, 0, sensor_cells
, id
,
377 dev_err(ec
->dev
, "failed to add EC sensors\n");
379 kfree(sensor_platforms
);
386 static const struct mfd_cell cros_ec_cec_cells
[] = {
387 { .name
= "cros-ec-cec" }
390 static const struct mfd_cell cros_ec_rtc_cells
[] = {
391 { .name
= "cros-ec-rtc" }
394 static const struct mfd_cell cros_usbpd_charger_cells
[] = {
395 { .name
= "cros-usbpd-charger" }
398 static int ec_device_probe(struct platform_device
*pdev
)
400 int retval
= -ENOMEM
;
401 struct device
*dev
= &pdev
->dev
;
402 struct cros_ec_platform
*ec_platform
= dev_get_platdata(dev
);
403 struct cros_ec_dev
*ec
= kzalloc(sizeof(*ec
), GFP_KERNEL
);
408 dev_set_drvdata(dev
, ec
);
409 ec
->ec_dev
= dev_get_drvdata(dev
->parent
);
411 ec
->cmd_offset
= ec_platform
->cmd_offset
;
412 ec
->features
[0] = -1U; /* Not cached yet */
413 ec
->features
[1] = -1U; /* Not cached yet */
414 device_initialize(&ec
->class_dev
);
415 cdev_init(&ec
->cdev
, &fops
);
418 * Add the class device
419 * Link to the character device for creating the /dev entry
422 ec
->class_dev
.devt
= MKDEV(ec_major
, pdev
->id
);
423 ec
->class_dev
.class = &cros_class
;
424 ec
->class_dev
.parent
= dev
;
425 ec
->class_dev
.release
= cros_ec_class_release
;
427 retval
= dev_set_name(&ec
->class_dev
, "%s", ec_platform
->ec_name
);
429 dev_err(dev
, "dev_set_name failed => %d\n", retval
);
433 /* check whether this EC is a sensor hub. */
434 if (cros_ec_check_features(ec
, EC_FEATURE_MOTION_SENSE
))
435 cros_ec_sensors_register(ec
);
437 /* Check whether this EC instance has CEC host command support */
438 if (cros_ec_check_features(ec
, EC_FEATURE_CEC
)) {
439 retval
= mfd_add_devices(ec
->dev
, PLATFORM_DEVID_AUTO
,
441 ARRAY_SIZE(cros_ec_cec_cells
),
445 "failed to add cros-ec-cec device: %d\n",
449 /* Check whether this EC instance has RTC host command support */
450 if (cros_ec_check_features(ec
, EC_FEATURE_RTC
)) {
451 retval
= mfd_add_devices(ec
->dev
, PLATFORM_DEVID_AUTO
,
453 ARRAY_SIZE(cros_ec_rtc_cells
),
457 "failed to add cros-ec-rtc device: %d\n",
461 /* Check whether this EC instance has the PD charge manager */
462 if (cros_ec_check_features(ec
, EC_FEATURE_USB_PD
)) {
463 retval
= mfd_add_devices(ec
->dev
, PLATFORM_DEVID_AUTO
,
464 cros_usbpd_charger_cells
,
465 ARRAY_SIZE(cros_usbpd_charger_cells
),
469 "failed to add cros-usbpd-charger device: %d\n",
473 /* Take control of the lightbar from the EC. */
474 lb_manual_suspend_ctrl(ec
, 1);
476 /* We can now add the sysfs class, we know which parameter to show */
477 retval
= cdev_device_add(&ec
->cdev
, &ec
->class_dev
);
479 dev_err(dev
, "cdev_device_add failed => %d\n", retval
);
483 if (cros_ec_debugfs_init(ec
))
484 dev_warn(dev
, "failed to create debugfs directory\n");
489 put_device(&ec
->class_dev
);
493 static int ec_device_remove(struct platform_device
*pdev
)
495 struct cros_ec_dev
*ec
= dev_get_drvdata(&pdev
->dev
);
497 /* Let the EC take over the lightbar again. */
498 lb_manual_suspend_ctrl(ec
, 0);
500 cros_ec_debugfs_remove(ec
);
502 mfd_remove_devices(ec
->dev
);
504 device_unregister(&ec
->class_dev
);
508 static void ec_device_shutdown(struct platform_device
*pdev
)
510 struct cros_ec_dev
*ec
= dev_get_drvdata(&pdev
->dev
);
512 /* Be sure to clear up debugfs delayed works */
513 cros_ec_debugfs_remove(ec
);
516 static const struct platform_device_id cros_ec_id
[] = {
520 MODULE_DEVICE_TABLE(platform
, cros_ec_id
);
522 static __maybe_unused
int ec_device_suspend(struct device
*dev
)
524 struct cros_ec_dev
*ec
= dev_get_drvdata(dev
);
526 cros_ec_debugfs_suspend(ec
);
533 static __maybe_unused
int ec_device_resume(struct device
*dev
)
535 struct cros_ec_dev
*ec
= dev_get_drvdata(dev
);
537 cros_ec_debugfs_resume(ec
);
544 static const struct dev_pm_ops cros_ec_dev_pm_ops
= {
545 #ifdef CONFIG_PM_SLEEP
546 .suspend
= ec_device_suspend
,
547 .resume
= ec_device_resume
,
551 static struct platform_driver cros_ec_dev_driver
= {
554 .pm
= &cros_ec_dev_pm_ops
,
556 .probe
= ec_device_probe
,
557 .remove
= ec_device_remove
,
558 .shutdown
= ec_device_shutdown
,
561 static int __init
cros_ec_dev_init(void)
566 ret
= class_register(&cros_class
);
568 pr_err(CROS_EC_DEV_NAME
": failed to register device class\n");
572 /* Get a range of minor numbers (starting with 0) to work with */
573 ret
= alloc_chrdev_region(&dev
, 0, CROS_MAX_DEV
, CROS_EC_DEV_NAME
);
575 pr_err(CROS_EC_DEV_NAME
": alloc_chrdev_region() failed\n");
576 goto failed_chrdevreg
;
578 ec_major
= MAJOR(dev
);
580 /* Register the driver */
581 ret
= platform_driver_register(&cros_ec_dev_driver
);
583 pr_warn(CROS_EC_DEV_NAME
": can't register driver: %d\n", ret
);
589 unregister_chrdev_region(MKDEV(ec_major
, 0), CROS_MAX_DEV
);
591 class_unregister(&cros_class
);
595 static void __exit
cros_ec_dev_exit(void)
597 platform_driver_unregister(&cros_ec_dev_driver
);
598 unregister_chrdev(ec_major
, CROS_EC_DEV_NAME
);
599 class_unregister(&cros_class
);
602 module_init(cros_ec_dev_init
);
603 module_exit(cros_ec_dev_exit
);
605 MODULE_ALIAS("platform:" DRV_NAME
);
606 MODULE_AUTHOR("Bill Richardson <wfrichar@chromium.org>");
607 MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller");
608 MODULE_VERSION("1.0");
609 MODULE_LICENSE("GPL");