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>
This commit is contained in:
Enric Balletbo i Serra 2018-12-12 18:33:57 +01:00 committed by Lee Jones
parent 4bc59c2f7e
commit ecf8a6cd94
7 changed files with 173 additions and 41 deletions

View File

@ -0,0 +1,74 @@
What: /sys/class/chromeos/<ec-device-name>/lightbar/brightness
Date: August 2015
KernelVersion: 4.2
Description:
Writing to this file adjusts the overall brightness of
the lightbar, separate from any color intensity. The
valid range is 0 (off) to 255 (maximum brightness).
What: /sys/class/chromeos/<ec-device-name>/lightbar/interval_msec
Date: August 2015
KernelVersion: 4.2
Description:
The lightbar is controlled by an embedded controller (EC),
which also manages the keyboard, battery charging, fans,
and other system hardware. To prevent unprivileged users
from interfering with the other EC functions, the rate at
which the lightbar control files can be read or written is
limited.
Reading this file will return the number of milliseconds
that must elapse between accessing any of the lightbar
functions through this interface. Going faster will simply
block until the necessary interval has lapsed. The interval
applies uniformly to all accesses of any kind by any user.
What: /sys/class/chromeos/<ec-device-name>/lightbar/led_rgb
Date: August 2015
KernelVersion: 4.2
Description:
This allows you to control each LED segment. If the
lightbar is already running one of the automatic
sequences, you probably wont see anything change because
your color setting will be almost immediately replaced.
To get useful results, you should stop the lightbar
sequence first.
The values written to this file are sets of four integers,
indicating LED, RED, GREEN, BLUE. The LED number is 0 to 3
to select a single segment, or 4 to set all four segments
to the same value at once. The RED, GREEN, and BLUE
numbers should be in the range 0 (off) to 255 (maximum).
You can update more than one segment at a time by writing
more than one set of four integers.
What: /sys/class/chromeos/<ec-device-name>/lightbar/program
Date: August 2015
KernelVersion: 4.2
Description:
This allows you to upload and run custom lightbar sequences.
What: /sys/class/chromeos/<ec-device-name>/lightbar/sequence
Date: August 2015
KernelVersion: 4.2
Description:
The Pixel lightbar has a number of built-in sequences
that it displays under various conditions, such as at
power on, shut down, or while running. Reading from this
file displays the current sequence that the lightbar is
displaying. Writing to this file allows you to change the
sequence.
What: /sys/class/chromeos/<ec-device-name>/lightbar/userspace_control
Date: August 2015
KernelVersion: 4.2
Description:
This allows you to take the control of the lightbar. This
prevents the kernel from going through its normal
sequences.
What: /sys/class/chromeos/<ec-device-name>/lightbar/version
Date: August 2015
KernelVersion: 4.2
Description:
Show the information about the lightbar version.

View File

@ -36,7 +36,6 @@ static int ec_major;
static const struct attribute_group *cros_ec_groups[] = {
&cros_ec_attr_group,
&cros_ec_lightbar_attr_group,
&cros_ec_vbc_attr_group,
NULL,
};
@ -395,6 +394,10 @@ static const struct mfd_cell cros_usbpd_charger_cells[] = {
{ .name = "cros-usbpd-charger" }
};
static const struct mfd_cell cros_ec_platform_cells[] = {
{ .name = "cros-ec-lightbar" },
};
static int ec_device_probe(struct platform_device *pdev)
{
int retval = -ENOMEM;
@ -470,9 +473,6 @@ static int ec_device_probe(struct platform_device *pdev)
retval);
}
/* Take control of the lightbar from the EC. */
lb_manual_suspend_ctrl(ec, 1);
/* We can now add the sysfs class, we know which parameter to show */
retval = cdev_device_add(&ec->cdev, &ec->class_dev);
if (retval) {
@ -480,6 +480,15 @@ static int ec_device_probe(struct platform_device *pdev)
goto failed;
}
retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO,
cros_ec_platform_cells,
ARRAY_SIZE(cros_ec_platform_cells),
NULL, 0, NULL);
if (retval)
dev_warn(ec->dev,
"failed to add cros-ec platform devices: %d\n",
retval);
if (cros_ec_debugfs_init(ec))
dev_warn(dev, "failed to create debugfs directory\n");
@ -494,9 +503,6 @@ static int ec_device_remove(struct platform_device *pdev)
{
struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
/* Let the EC take over the lightbar again. */
lb_manual_suspend_ctrl(ec, 0);
cros_ec_debugfs_remove(ec);
mfd_remove_devices(ec->dev);
@ -525,8 +531,6 @@ static __maybe_unused int ec_device_suspend(struct device *dev)
cros_ec_debugfs_suspend(ec);
lb_suspend(ec);
return 0;
}
@ -536,8 +540,6 @@ static __maybe_unused int ec_device_resume(struct device *dev)
cros_ec_debugfs_resume(ec);
lb_resume(ec);
return 0;
}

View File

@ -44,10 +44,4 @@ struct cros_ec_readmem {
#define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command)
#define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem)
/* Lightbar utilities */
extern bool ec_has_lightbar(struct cros_ec_dev *ec);
extern int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable);
extern int lb_suspend(struct cros_ec_dev *ec);
extern int lb_resume(struct cros_ec_dev *ec);
#endif /* _CROS_EC_DEV_H_ */

View File

@ -111,4 +111,15 @@ config CROS_KBD_LED_BACKLIGHT
To compile this driver as a module, choose M here: the
module will be called cros_kbd_led_backlight.
config CROS_EC_LIGHTBAR
tristate "Chromebook Pixel's lightbar support"
depends on MFD_CROS_EC_CHARDEV
default MFD_CROS_EC_CHARDEV
help
This option exposes the Chromebook Pixel's lightbar to
userspace.
To compile this driver as a module, choose M here: the
module will be called cros_ec_lightbar.
endif # CHROMEOS_PLATFORMS

View File

@ -3,7 +3,7 @@
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o
cros_ec_ctl-objs := cros_ec_sysfs.o cros_ec_lightbar.o \
cros_ec_ctl-objs := cros_ec_sysfs.o \
cros_ec_vbc.o cros_ec_debugfs.o
obj-$(CONFIG_CROS_EC_CTL) += cros_ec_ctl.o
obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
@ -13,3 +13,4 @@ cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o
obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o
obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o
obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o

View File

@ -33,6 +33,8 @@
#include <linux/uaccess.h>
#include <linux/slab.h>
#define DRV_NAME "cros-ec-lightbar"
/* Rate-limit the lightbar interface to prevent DoS. */
static unsigned long lb_interval_jiffies = 50 * HZ / 1000;
@ -373,7 +375,7 @@ static int lb_send_empty_cmd(struct cros_ec_dev *ec, uint8_t cmd)
return ret;
}
int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
static int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
{
struct ec_params_lightbar *param;
struct cros_ec_command *msg;
@ -408,25 +410,6 @@ int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
return ret;
}
EXPORT_SYMBOL(lb_manual_suspend_ctrl);
int lb_suspend(struct cros_ec_dev *ec)
{
if (userspace_control || ec != ec_with_lightbar)
return 0;
return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND);
}
EXPORT_SYMBOL(lb_suspend);
int lb_resume(struct cros_ec_dev *ec)
{
if (userspace_control || ec != ec_with_lightbar)
return 0;
return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME);
}
EXPORT_SYMBOL(lb_resume);
static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@ -584,7 +567,7 @@ static struct attribute *__lb_cmds_attrs[] = {
NULL,
};
bool ec_has_lightbar(struct cros_ec_dev *ec)
static bool ec_has_lightbar(struct cros_ec_dev *ec)
{
return !!get_lightbar_version(ec, NULL, NULL);
}
@ -616,4 +599,72 @@ struct attribute_group cros_ec_lightbar_attr_group = {
.attrs = __lb_cmds_attrs,
.is_visible = cros_ec_lightbar_attrs_are_visible,
};
EXPORT_SYMBOL(cros_ec_lightbar_attr_group);
static int cros_ec_lightbar_probe(struct platform_device *pd)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
struct device *dev = &pd->dev;
int ret;
/* Take control of the lightbar from the EC. */
lb_manual_suspend_ctrl(ec_dev, 1);
ret = sysfs_create_group(&ec_dev->class_dev.kobj,
&cros_ec_lightbar_attr_group);
if (ret < 0)
dev_err(dev, "failed to create %s attributes. err=%d\n",
cros_ec_lightbar_attr_group.name, ret);
return ret;
}
static int cros_ec_lightbar_remove(struct platform_device *pd)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
sysfs_remove_group(&ec_dev->class_dev.kobj,
&cros_ec_lightbar_attr_group);
/* Let the EC take over the lightbar again. */
lb_manual_suspend_ctrl(ec_dev, 0);
return 0;
}
static int __maybe_unused cros_ec_lightbar_resume(struct device *dev)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev);
if (userspace_control || ec_dev != ec_with_lightbar)
return 0;
return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_RESUME);
}
static int __maybe_unused cros_ec_lightbar_suspend(struct device *dev)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev);
if (userspace_control || ec_dev != ec_with_lightbar)
return 0;
return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_SUSPEND);
}
static SIMPLE_DEV_PM_OPS(cros_ec_lightbar_pm_ops,
cros_ec_lightbar_suspend, cros_ec_lightbar_resume);
static struct platform_driver cros_ec_lightbar_driver = {
.driver = {
.name = DRV_NAME,
.pm = &cros_ec_lightbar_pm_ops,
},
.probe = cros_ec_lightbar_probe,
.remove = cros_ec_lightbar_remove,
};
module_platform_driver(cros_ec_lightbar_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Expose the Chromebook Pixel's lightbar to userspace");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -327,7 +327,6 @@ u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
/* sysfs stuff */
extern struct attribute_group cros_ec_attr_group;
extern struct attribute_group cros_ec_lightbar_attr_group;
extern struct attribute_group cros_ec_vbc_attr_group;
/* debugfs stuff */