Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd / platform: cros_ec: Move lightbar attributes to its own driver

The entire way how cros sysfs attibutes are created is broken.
cros_ec_lightbar should be its own driver and its attributes should be
associated with a lightbar driver not the mfd driver. In order to retain
the path, the lightbar attributes are attached to the cros_class.

The patch also adds the sysfs documentation.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Guenter Roeck <groeck@chromium.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Enric Balletbo i Serra and committed by
Lee Jones
ecf8a6cd 4bc59c2f

+173 -41
+74
Documentation/ABI/testing/sysfs-class-chromeos-driver-cros-ec-lightbar
··· 1 + What: /sys/class/chromeos/<ec-device-name>/lightbar/brightness 2 + Date: August 2015 3 + KernelVersion: 4.2 4 + Description: 5 + Writing to this file adjusts the overall brightness of 6 + the lightbar, separate from any color intensity. The 7 + valid range is 0 (off) to 255 (maximum brightness). 8 + 9 + What: /sys/class/chromeos/<ec-device-name>/lightbar/interval_msec 10 + Date: August 2015 11 + KernelVersion: 4.2 12 + Description: 13 + The lightbar is controlled by an embedded controller (EC), 14 + which also manages the keyboard, battery charging, fans, 15 + and other system hardware. To prevent unprivileged users 16 + from interfering with the other EC functions, the rate at 17 + which the lightbar control files can be read or written is 18 + limited. 19 + 20 + Reading this file will return the number of milliseconds 21 + that must elapse between accessing any of the lightbar 22 + functions through this interface. Going faster will simply 23 + block until the necessary interval has lapsed. The interval 24 + applies uniformly to all accesses of any kind by any user. 25 + 26 + What: /sys/class/chromeos/<ec-device-name>/lightbar/led_rgb 27 + Date: August 2015 28 + KernelVersion: 4.2 29 + Description: 30 + This allows you to control each LED segment. If the 31 + lightbar is already running one of the automatic 32 + sequences, you probably won’t see anything change because 33 + your color setting will be almost immediately replaced. 34 + To get useful results, you should stop the lightbar 35 + sequence first. 36 + 37 + The values written to this file are sets of four integers, 38 + indicating LED, RED, GREEN, BLUE. The LED number is 0 to 3 39 + to select a single segment, or 4 to set all four segments 40 + to the same value at once. The RED, GREEN, and BLUE 41 + numbers should be in the range 0 (off) to 255 (maximum). 42 + You can update more than one segment at a time by writing 43 + more than one set of four integers. 44 + 45 + What: /sys/class/chromeos/<ec-device-name>/lightbar/program 46 + Date: August 2015 47 + KernelVersion: 4.2 48 + Description: 49 + This allows you to upload and run custom lightbar sequences. 50 + 51 + What: /sys/class/chromeos/<ec-device-name>/lightbar/sequence 52 + Date: August 2015 53 + KernelVersion: 4.2 54 + Description: 55 + The Pixel lightbar has a number of built-in sequences 56 + that it displays under various conditions, such as at 57 + power on, shut down, or while running. Reading from this 58 + file displays the current sequence that the lightbar is 59 + displaying. Writing to this file allows you to change the 60 + sequence. 61 + 62 + What: /sys/class/chromeos/<ec-device-name>/lightbar/userspace_control 63 + Date: August 2015 64 + KernelVersion: 4.2 65 + Description: 66 + This allows you to take the control of the lightbar. This 67 + prevents the kernel from going through its normal 68 + sequences. 69 + 70 + What: /sys/class/chromeos/<ec-device-name>/lightbar/version 71 + Date: August 2015 72 + KernelVersion: 4.2 73 + Description: 74 + Show the information about the lightbar version.
+13 -11
drivers/mfd/cros_ec_dev.c
··· 36 36 37 37 static const struct attribute_group *cros_ec_groups[] = { 38 38 &cros_ec_attr_group, 39 - &cros_ec_lightbar_attr_group, 40 39 &cros_ec_vbc_attr_group, 41 40 NULL, 42 41 }; ··· 394 395 { .name = "cros-usbpd-charger" } 395 396 }; 396 397 398 + static const struct mfd_cell cros_ec_platform_cells[] = { 399 + { .name = "cros-ec-lightbar" }, 400 + }; 401 + 397 402 static int ec_device_probe(struct platform_device *pdev) 398 403 { 399 404 int retval = -ENOMEM; ··· 473 470 retval); 474 471 } 475 472 476 - /* Take control of the lightbar from the EC. */ 477 - lb_manual_suspend_ctrl(ec, 1); 478 - 479 473 /* We can now add the sysfs class, we know which parameter to show */ 480 474 retval = cdev_device_add(&ec->cdev, &ec->class_dev); 481 475 if (retval) { 482 476 dev_err(dev, "cdev_device_add failed => %d\n", retval); 483 477 goto failed; 484 478 } 479 + 480 + retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, 481 + cros_ec_platform_cells, 482 + ARRAY_SIZE(cros_ec_platform_cells), 483 + NULL, 0, NULL); 484 + if (retval) 485 + dev_warn(ec->dev, 486 + "failed to add cros-ec platform devices: %d\n", 487 + retval); 485 488 486 489 if (cros_ec_debugfs_init(ec)) 487 490 dev_warn(dev, "failed to create debugfs directory\n"); ··· 502 493 static int ec_device_remove(struct platform_device *pdev) 503 494 { 504 495 struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); 505 - 506 - /* Let the EC take over the lightbar again. */ 507 - lb_manual_suspend_ctrl(ec, 0); 508 496 509 497 cros_ec_debugfs_remove(ec); 510 498 ··· 531 525 532 526 cros_ec_debugfs_suspend(ec); 533 527 534 - lb_suspend(ec); 535 - 536 528 return 0; 537 529 } 538 530 ··· 539 535 struct cros_ec_dev *ec = dev_get_drvdata(dev); 540 536 541 537 cros_ec_debugfs_resume(ec); 542 - 543 - lb_resume(ec); 544 538 545 539 return 0; 546 540 }
-6
drivers/mfd/cros_ec_dev.h
··· 44 44 #define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command) 45 45 #define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem) 46 46 47 - /* Lightbar utilities */ 48 - extern bool ec_has_lightbar(struct cros_ec_dev *ec); 49 - extern int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable); 50 - extern int lb_suspend(struct cros_ec_dev *ec); 51 - extern int lb_resume(struct cros_ec_dev *ec); 52 - 53 47 #endif /* _CROS_EC_DEV_H_ */
+11
drivers/platform/chrome/Kconfig
··· 111 111 To compile this driver as a module, choose M here: the 112 112 module will be called cros_kbd_led_backlight. 113 113 114 + config CROS_EC_LIGHTBAR 115 + tristate "Chromebook Pixel's lightbar support" 116 + depends on MFD_CROS_EC_CHARDEV 117 + default MFD_CROS_EC_CHARDEV 118 + help 119 + This option exposes the Chromebook Pixel's lightbar to 120 + userspace. 121 + 122 + To compile this driver as a module, choose M here: the 123 + module will be called cros_ec_lightbar. 124 + 114 125 endif # CHROMEOS_PLATFORMS
+2 -1
drivers/platform/chrome/Makefile
··· 3 3 obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o 4 4 obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o 5 5 obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o 6 - cros_ec_ctl-objs := cros_ec_sysfs.o cros_ec_lightbar.o \ 6 + cros_ec_ctl-objs := cros_ec_sysfs.o \ 7 7 cros_ec_vbc.o cros_ec_debugfs.o 8 8 obj-$(CONFIG_CROS_EC_CTL) += cros_ec_ctl.o 9 9 obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o ··· 13 13 obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o 14 14 obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o 15 15 obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o 16 + obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o
+73 -22
drivers/platform/chrome/cros_ec_lightbar.c
··· 33 33 #include <linux/uaccess.h> 34 34 #include <linux/slab.h> 35 35 36 + #define DRV_NAME "cros-ec-lightbar" 37 + 36 38 /* Rate-limit the lightbar interface to prevent DoS. */ 37 39 static unsigned long lb_interval_jiffies = 50 * HZ / 1000; 38 40 ··· 375 373 return ret; 376 374 } 377 375 378 - int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable) 376 + static int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable) 379 377 { 380 378 struct ec_params_lightbar *param; 381 379 struct cros_ec_command *msg; ··· 410 408 411 409 return ret; 412 410 } 413 - EXPORT_SYMBOL(lb_manual_suspend_ctrl); 414 - 415 - int lb_suspend(struct cros_ec_dev *ec) 416 - { 417 - if (userspace_control || ec != ec_with_lightbar) 418 - return 0; 419 - 420 - return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND); 421 - } 422 - EXPORT_SYMBOL(lb_suspend); 423 - 424 - int lb_resume(struct cros_ec_dev *ec) 425 - { 426 - if (userspace_control || ec != ec_with_lightbar) 427 - return 0; 428 - 429 - return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME); 430 - } 431 - EXPORT_SYMBOL(lb_resume); 432 411 433 412 static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, 434 413 const char *buf, size_t count) ··· 567 584 NULL, 568 585 }; 569 586 570 - bool ec_has_lightbar(struct cros_ec_dev *ec) 587 + static bool ec_has_lightbar(struct cros_ec_dev *ec) 571 588 { 572 589 return !!get_lightbar_version(ec, NULL, NULL); 573 590 } ··· 599 616 .attrs = __lb_cmds_attrs, 600 617 .is_visible = cros_ec_lightbar_attrs_are_visible, 601 618 }; 602 - EXPORT_SYMBOL(cros_ec_lightbar_attr_group); 619 + 620 + static int cros_ec_lightbar_probe(struct platform_device *pd) 621 + { 622 + struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent); 623 + struct device *dev = &pd->dev; 624 + int ret; 625 + 626 + /* Take control of the lightbar from the EC. */ 627 + lb_manual_suspend_ctrl(ec_dev, 1); 628 + 629 + ret = sysfs_create_group(&ec_dev->class_dev.kobj, 630 + &cros_ec_lightbar_attr_group); 631 + if (ret < 0) 632 + dev_err(dev, "failed to create %s attributes. err=%d\n", 633 + cros_ec_lightbar_attr_group.name, ret); 634 + 635 + return ret; 636 + } 637 + 638 + static int cros_ec_lightbar_remove(struct platform_device *pd) 639 + { 640 + struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent); 641 + 642 + sysfs_remove_group(&ec_dev->class_dev.kobj, 643 + &cros_ec_lightbar_attr_group); 644 + 645 + /* Let the EC take over the lightbar again. */ 646 + lb_manual_suspend_ctrl(ec_dev, 0); 647 + 648 + return 0; 649 + } 650 + 651 + static int __maybe_unused cros_ec_lightbar_resume(struct device *dev) 652 + { 653 + struct cros_ec_dev *ec_dev = dev_get_drvdata(dev); 654 + 655 + if (userspace_control || ec_dev != ec_with_lightbar) 656 + return 0; 657 + 658 + return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_RESUME); 659 + } 660 + 661 + static int __maybe_unused cros_ec_lightbar_suspend(struct device *dev) 662 + { 663 + struct cros_ec_dev *ec_dev = dev_get_drvdata(dev); 664 + 665 + if (userspace_control || ec_dev != ec_with_lightbar) 666 + return 0; 667 + 668 + return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_SUSPEND); 669 + } 670 + 671 + static SIMPLE_DEV_PM_OPS(cros_ec_lightbar_pm_ops, 672 + cros_ec_lightbar_suspend, cros_ec_lightbar_resume); 673 + 674 + static struct platform_driver cros_ec_lightbar_driver = { 675 + .driver = { 676 + .name = DRV_NAME, 677 + .pm = &cros_ec_lightbar_pm_ops, 678 + }, 679 + .probe = cros_ec_lightbar_probe, 680 + .remove = cros_ec_lightbar_remove, 681 + }; 682 + 683 + module_platform_driver(cros_ec_lightbar_driver); 684 + 685 + MODULE_LICENSE("GPL"); 686 + MODULE_DESCRIPTION("Expose the Chromebook Pixel's lightbar to userspace"); 687 + MODULE_ALIAS("platform:" DRV_NAME);
-1
include/linux/mfd/cros_ec.h
··· 327 327 328 328 /* sysfs stuff */ 329 329 extern struct attribute_group cros_ec_attr_group; 330 - extern struct attribute_group cros_ec_lightbar_attr_group; 331 330 extern struct attribute_group cros_ec_vbc_attr_group; 332 331 333 332 /* debugfs stuff */