aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
authorMark Brown <broonie@kernel.org>2026-05-29 23:00:16 +0100
committerMark Brown <broonie@kernel.org>2026-05-29 23:00:16 +0100
commit998d686acbb9c44fb2ed370e5371e1da1f15c2e1 (patch)
tree72c59be33d601bc1b2368373b299e725f9cfc6e8 /drivers
parent166f6eabaab65d0625b28dfafe72b76d44027977 (diff)
parent4178de898c341e6c259851a2be1c7649ac4f40ad (diff)
downloadlinux-next-history-998d686acbb9c44fb2ed370e5371e1da1f15c2e1.tar.gz
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git
Diffstat (limited to 'drivers')
-rw-r--r--drivers/platform/chrome/chromeos_privacy_screen.c3
-rw-r--r--drivers/platform/chrome/chromeos_tbmc.c6
-rw-r--r--drivers/platform/chrome/cros_ec_chardev.c146
-rw-r--r--drivers/platform/chrome/cros_ec_i2c.c2
-rw-r--r--drivers/platform/chrome/cros_ec_sensorhub.c6
-rw-r--r--drivers/platform/chrome/cros_ec_sysfs.c5
-rw-r--r--drivers/platform/chrome/cros_hps_i2c.c2
-rw-r--r--drivers/platform/chrome/cros_kbd_led_backlight.c28
-rw-r--r--drivers/platform/chrome/wilco_ec/event.c8
9 files changed, 147 insertions, 59 deletions
diff --git a/drivers/platform/chrome/chromeos_privacy_screen.c b/drivers/platform/chrome/chromeos_privacy_screen.c
index abc5d189a3894..407b04207de2f 100644
--- a/drivers/platform/chrome/chromeos_privacy_screen.c
+++ b/drivers/platform/chrome/chromeos_privacy_screen.c
@@ -104,6 +104,9 @@ static const struct drm_privacy_screen_ops chromeos_privacy_screen_ops = {
static int chromeos_privacy_screen_probe(struct platform_device *pdev)
{
+ if (!ACPI_COMPANION(&pdev->dev))
+ return -ENODEV;
+
struct drm_privacy_screen *drm_privacy_screen =
drm_privacy_screen_register(&pdev->dev,
&chromeos_privacy_screen_ops,
diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c
index 5133806b2d958..fd756761a481f 100644
--- a/drivers/platform/chrome/chromeos_tbmc.c
+++ b/drivers/platform/chrome/chromeos_tbmc.c
@@ -69,9 +69,13 @@ static int chromeos_tbmc_probe(struct platform_device *pdev)
{
struct input_dev *idev;
struct device *dev = &pdev->dev;
- struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct acpi_device *adev;
int ret;
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return -ENODEV;
+
idev = devm_input_allocate_device(dev);
if (!idev)
return -ENOMEM;
diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
index 002be33521005..47e03014dcbe7 100644
--- a/drivers/platform/chrome/cros_ec_chardev.c
+++ b/drivers/platform/chrome/cros_ec_chardev.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fs.h>
+#include <linux/kref.h>
#include <linux/miscdevice.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
@@ -22,6 +23,7 @@
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
#include <linux/poll.h>
+#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
@@ -31,14 +33,44 @@
/* Arbitrary bounded size for the event queue */
#define CROS_MAX_EVENT_LEN PAGE_SIZE
-struct chardev_priv {
+/*
+ * Platform device driver data.
+ */
+struct chardev_pdata {
+ struct miscdevice misc;
+ struct kref kref;
+ struct rw_semaphore ec_dev_sem;
struct cros_ec_device *ec_dev;
+ u16 cmd_offset;
+ struct blocking_notifier_head subscribers;
+ struct notifier_block relay;
+};
+
+static void chardev_pdata_release(struct kref *kref)
+{
+ struct chardev_pdata *pdata = container_of(kref, typeof(*pdata), kref);
+
+ kfree(pdata);
+}
+
+static int cros_ec_chardev_relay_event(struct notifier_block *nb,
+ unsigned long queued_during_suspend,
+ void *_notify)
+{
+ struct chardev_pdata *pdata = container_of(nb, typeof(*pdata), relay);
+
+ blocking_notifier_call_chain(&pdata->subscribers, queued_during_suspend,
+ _notify);
+ return NOTIFY_OK;
+}
+
+struct chardev_priv {
struct notifier_block notifier;
wait_queue_head_t wait_event;
unsigned long event_mask;
struct list_head events;
size_t event_len;
- u16 cmd_offset;
+ struct chardev_pdata *pdata;
};
struct ec_event {
@@ -61,10 +93,10 @@ static int ec_get_version(struct chardev_priv *priv, char *str, int maxlen)
if (!msg)
return -ENOMEM;
- msg->command = EC_CMD_GET_VERSION + priv->cmd_offset;
+ msg->command = EC_CMD_GET_VERSION + priv->pdata->cmd_offset;
msg->insize = sizeof(*resp);
- ret = cros_ec_cmd_xfer_status(priv->ec_dev, msg);
+ ret = cros_ec_cmd_xfer_status(priv->pdata->ec_dev, msg);
if (ret < 0) {
snprintf(str, maxlen,
"Unknown EC version, returned error: %d\n",
@@ -92,10 +124,18 @@ static int cros_ec_chardev_mkbp_event(struct notifier_block *nb,
{
struct chardev_priv *priv = container_of(nb, struct chardev_priv,
notifier);
- struct cros_ec_device *ec_dev = priv->ec_dev;
+ struct cros_ec_device *ec_dev;
struct ec_event *event;
- unsigned long event_bit = 1 << ec_dev->event_data.event_type;
- int total_size = sizeof(*event) + ec_dev->event_size;
+ unsigned long event_bit;
+ int total_size;
+
+ guard(rwsem_read)(&priv->pdata->ec_dev_sem);
+ if (!priv->pdata->ec_dev)
+ return NOTIFY_DONE;
+ ec_dev = priv->pdata->ec_dev;
+
+ event_bit = 1 << ec_dev->event_data.event_type;
+ total_size = sizeof(*event) + ec_dev->event_size;
if (!(event_bit & priv->event_mask) ||
(priv->event_len + total_size) > CROS_MAX_EVENT_LEN)
@@ -157,8 +197,7 @@ out:
static int cros_ec_chardev_open(struct inode *inode, struct file *filp)
{
struct miscdevice *mdev = filp->private_data;
- struct cros_ec_dev *ec = dev_get_drvdata(mdev->parent);
- struct cros_ec_device *ec_dev = ec->ec_dev;
+ struct chardev_pdata *pdata = container_of(mdev, typeof(*pdata), misc);
struct chardev_priv *priv;
int ret;
@@ -166,18 +205,20 @@ static int cros_ec_chardev_open(struct inode *inode, struct file *filp)
if (!priv)
return -ENOMEM;
- priv->ec_dev = ec_dev;
- priv->cmd_offset = ec->cmd_offset;
+ priv->pdata = pdata;
+ kref_get(&pdata->kref);
filp->private_data = priv;
INIT_LIST_HEAD(&priv->events);
init_waitqueue_head(&priv->wait_event);
nonseekable_open(inode, filp);
priv->notifier.notifier_call = cros_ec_chardev_mkbp_event;
- ret = blocking_notifier_chain_register(&ec_dev->event_notifier,
+ ret = blocking_notifier_chain_register(&pdata->subscribers,
&priv->notifier);
if (ret) {
- dev_err(ec_dev->dev, "failed to register event notifier\n");
+ dev_err(pdata->ec_dev->dev,
+ "failed to register event notifier\n");
+ kref_put(&priv->pdata->kref, chardev_pdata_release);
kfree(priv);
}
@@ -188,6 +229,10 @@ static __poll_t cros_ec_chardev_poll(struct file *filp, poll_table *wait)
{
struct chardev_priv *priv = filp->private_data;
+ guard(rwsem_read)(&priv->pdata->ec_dev_sem);
+ if (!priv->pdata->ec_dev)
+ return EPOLLHUP;
+
poll_wait(filp, &priv->wait_event, wait);
if (list_empty(&priv->events))
@@ -205,6 +250,10 @@ static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer,
size_t count;
int ret;
+ guard(rwsem_read)(&priv->pdata->ec_dev_sem);
+ if (!priv->pdata->ec_dev)
+ return -ENODEV;
+
if (priv->event_mask) { /* queued MKBP event */
struct ec_event *event;
@@ -251,11 +300,11 @@ static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer,
static int cros_ec_chardev_release(struct inode *inode, struct file *filp)
{
struct chardev_priv *priv = filp->private_data;
- struct cros_ec_device *ec_dev = priv->ec_dev;
struct ec_event *event, *e;
- blocking_notifier_chain_unregister(&ec_dev->event_notifier,
+ blocking_notifier_chain_unregister(&priv->pdata->subscribers,
&priv->notifier);
+ kref_put(&priv->pdata->kref, chardev_pdata_release);
list_for_each_entry_safe(event, e, &priv->events, node) {
list_del(&event->node);
@@ -298,8 +347,8 @@ static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *a
goto exit;
}
- s_cmd->command += priv->cmd_offset;
- ret = cros_ec_cmd_xfer(priv->ec_dev, s_cmd);
+ s_cmd->command += priv->pdata->cmd_offset;
+ ret = cros_ec_cmd_xfer(priv->pdata->ec_dev, s_cmd);
/* Only copy data to userland if data was received. */
if (ret < 0)
goto exit;
@@ -313,7 +362,7 @@ exit:
static long cros_ec_chardev_ioctl_readmem(struct chardev_priv *priv, void __user *arg)
{
- struct cros_ec_device *ec_dev = priv->ec_dev;
+ struct cros_ec_device *ec_dev = priv->pdata->ec_dev;
struct cros_ec_readmem s_mem = { };
long num;
@@ -343,6 +392,10 @@ static long cros_ec_chardev_ioctl(struct file *filp, unsigned int cmd,
{
struct chardev_priv *priv = filp->private_data;
+ guard(rwsem_read)(&priv->pdata->ec_dev_sem);
+ if (!priv->pdata->ec_dev)
+ return -ENODEV;
+
if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC)
return -ENOTTY;
@@ -374,28 +427,61 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
{
struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent);
struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
- struct miscdevice *misc;
+ struct chardev_pdata *pdata;
+ int ret;
- /* Create a char device: we want to create it anew */
- misc = devm_kzalloc(&pdev->dev, sizeof(*misc), GFP_KERNEL);
- if (!misc)
+ pdata = kzalloc_obj(*pdata);
+ if (!pdata)
return -ENOMEM;
- misc->minor = MISC_DYNAMIC_MINOR;
- misc->fops = &chardev_fops;
- misc->name = ec_platform->ec_name;
- misc->parent = pdev->dev.parent;
+ platform_set_drvdata(pdev, pdata);
+ kref_init(&pdata->kref);
+ init_rwsem(&pdata->ec_dev_sem);
+ pdata->ec_dev = ec->ec_dev;
+ pdata->cmd_offset = ec->cmd_offset;
+ BLOCKING_INIT_NOTIFIER_HEAD(&pdata->subscribers);
+ pdata->relay.notifier_call = cros_ec_chardev_relay_event;
+ ret = blocking_notifier_chain_register(&pdata->ec_dev->event_notifier,
+ &pdata->relay);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register event notifier\n");
+ goto err_put_pdata;
+ }
+
+ pdata->misc.minor = MISC_DYNAMIC_MINOR;
+ pdata->misc.fops = &chardev_fops;
+ pdata->misc.name = ec_platform->ec_name;
+ pdata->misc.parent = pdev->dev.parent;
- dev_set_drvdata(&pdev->dev, misc);
+ ret = misc_register(&pdata->misc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register misc device\n");
+ goto err_unregister_notifier;
+ }
- return misc_register(misc);
+ return 0;
+err_unregister_notifier:
+ blocking_notifier_chain_unregister(&pdata->ec_dev->event_notifier,
+ &pdata->relay);
+err_put_pdata:
+ kref_put(&pdata->kref, chardev_pdata_release);
+ return ret;
}
static void cros_ec_chardev_remove(struct platform_device *pdev)
{
- struct miscdevice *misc = dev_get_drvdata(&pdev->dev);
+ struct chardev_pdata *pdata = platform_get_drvdata(pdev);
+ struct cros_ec_device *ec_dev = pdata->ec_dev;
- misc_deregister(misc);
+ /* stop new fops from being created */
+ misc_deregister(&pdata->misc);
+ /* stop existing fops from running */
+ scoped_guard(rwsem_write, &pdata->ec_dev_sem)
+ pdata->ec_dev = NULL;
+
+ blocking_notifier_chain_unregister(&ec_dev->event_notifier,
+ &pdata->relay);
+ kref_put(&pdata->kref, chardev_pdata_release);
}
static const struct platform_device_id cros_ec_chardev_id[] = {
diff --git a/drivers/platform/chrome/cros_ec_i2c.c b/drivers/platform/chrome/cros_ec_i2c.c
index def1144a077ea..2f46be4a27569 100644
--- a/drivers/platform/chrome/cros_ec_i2c.c
+++ b/drivers/platform/chrome/cros_ec_i2c.c
@@ -348,7 +348,7 @@ MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match);
#endif
static const struct i2c_device_id cros_ec_i2c_id[] = {
- { "cros-ec-i2c" },
+ { .name = "cros-ec-i2c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id);
diff --git a/drivers/platform/chrome/cros_ec_sensorhub.c b/drivers/platform/chrome/cros_ec_sensorhub.c
index 9bad8f72680ea..f938c3fc84e4f 100644
--- a/drivers/platform/chrome/cros_ec_sensorhub.c
+++ b/drivers/platform/chrome/cros_ec_sensorhub.c
@@ -122,8 +122,12 @@ static int cros_ec_sensorhub_register(struct device *dev,
sensor_type[sensorhub->resp->info.type]++;
}
- if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
+ if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) {
ec->has_kb_wake_angle = true;
+ if (ec->group && sysfs_update_group(&ec->class_dev.kobj,
+ ec->group))
+ dev_warn(dev, "Unable to update sysfs");
+ }
if (cros_ec_check_features(ec,
EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) {
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
index f22e9523da3e8..9d3767ab15480 100644
--- a/drivers/platform/chrome/cros_ec_sysfs.c
+++ b/drivers/platform/chrome/cros_ec_sysfs.c
@@ -405,7 +405,8 @@ static int cros_ec_sysfs_probe(struct platform_device *pd)
struct device *dev = &pd->dev;
int ret;
- ret = sysfs_create_group(&ec_dev->class_dev.kobj, &cros_ec_attr_group);
+ ec_dev->group = &cros_ec_attr_group;
+ ret = sysfs_create_group(&ec_dev->class_dev.kobj, ec_dev->group);
if (ret < 0)
dev_err(dev, "failed to create attributes. err=%d\n", ret);
@@ -416,7 +417,7 @@ static void cros_ec_sysfs_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_attr_group);
+ sysfs_remove_group(&ec_dev->class_dev.kobj, ec_dev->group);
}
static const struct platform_device_id cros_ec_sysfs_id[] = {
diff --git a/drivers/platform/chrome/cros_hps_i2c.c b/drivers/platform/chrome/cros_hps_i2c.c
index ac6498c593e3f..3b94856278312 100644
--- a/drivers/platform/chrome/cros_hps_i2c.c
+++ b/drivers/platform/chrome/cros_hps_i2c.c
@@ -131,7 +131,7 @@ static int hps_resume(struct device *dev)
static DEFINE_RUNTIME_DEV_PM_OPS(hps_pm_ops, hps_suspend, hps_resume, NULL);
static const struct i2c_device_id hps_i2c_id[] = {
- { "cros-hps" },
+ { .name = "cros-hps" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hps_i2c_id);
diff --git a/drivers/platform/chrome/cros_kbd_led_backlight.c b/drivers/platform/chrome/cros_kbd_led_backlight.c
index f4c2282129f50..80dc52833dc99 100644
--- a/drivers/platform/chrome/cros_kbd_led_backlight.c
+++ b/drivers/platform/chrome/cros_kbd_led_backlight.c
@@ -32,12 +32,11 @@ struct keyboard_led {
* @brightness_set_blocking: Set LED brightness level. It can block the
* caller for the time required for accessing a
* LED device register
- * @max_brightness: Maximum brightness.
*
* See struct led_classdev in include/linux/leds.h for more details.
*/
struct keyboard_led_drvdata {
- int (*init)(struct platform_device *pdev);
+ int (*init)(struct platform_device *pdev, struct keyboard_led *keyboard_led);
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
@@ -45,12 +44,8 @@ struct keyboard_led_drvdata {
enum led_brightness brightness);
int (*brightness_set_blocking)(struct led_classdev *led_cdev,
enum led_brightness brightness);
-
- enum led_brightness max_brightness;
};
-#define KEYBOARD_BACKLIGHT_MAX 100
-
#ifdef CONFIG_ACPI
/* Keyboard LED ACPI Device must be defined in firmware */
@@ -94,7 +89,8 @@ keyboard_led_get_brightness_acpi(struct led_classdev *cdev)
return brightness;
}
-static int keyboard_led_init_acpi(struct platform_device *pdev)
+static int keyboard_led_init_acpi(struct platform_device *pdev,
+ struct keyboard_led *keyboard_led)
{
acpi_handle handle;
acpi_status status;
@@ -116,17 +112,15 @@ static const struct keyboard_led_drvdata keyboard_led_drvdata_acpi = {
.init = keyboard_led_init_acpi,
.brightness_set = keyboard_led_set_brightness_acpi,
.brightness_get = keyboard_led_get_brightness_acpi,
- .max_brightness = KEYBOARD_BACKLIGHT_MAX,
};
#endif /* CONFIG_ACPI */
-#if IS_ENABLED(CONFIG_MFD_CROS_EC_DEV)
-static int keyboard_led_init_ec_pwm_mfd(struct platform_device *pdev)
+static int keyboard_led_init_ec_pwm_mfd(struct platform_device *pdev,
+ struct keyboard_led *keyboard_led)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent);
struct cros_ec_device *cros_ec = ec_dev->ec_dev;
- struct keyboard_led *keyboard_led = platform_get_drvdata(pdev);
keyboard_led->ec = cros_ec;
@@ -175,15 +169,8 @@ static const struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm_mfd = {
.init = keyboard_led_init_ec_pwm_mfd,
.brightness_set_blocking = keyboard_led_set_brightness_ec_pwm,
.brightness_get = keyboard_led_get_brightness_ec_pwm,
- .max_brightness = KEYBOARD_BACKLIGHT_MAX,
};
-#else /* IS_ENABLED(CONFIG_MFD_CROS_EC_DEV) */
-
-static const struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm_mfd = {};
-
-#endif /* IS_ENABLED(CONFIG_MFD_CROS_EC_DEV) */
-
static int keyboard_led_is_mfd_device(struct platform_device *pdev)
{
return IS_ENABLED(CONFIG_MFD_CROS_EC_DEV) && mfd_get_cell(pdev);
@@ -205,17 +192,16 @@ static int keyboard_led_probe(struct platform_device *pdev)
keyboard_led = devm_kzalloc(&pdev->dev, sizeof(*keyboard_led), GFP_KERNEL);
if (!keyboard_led)
return -ENOMEM;
- platform_set_drvdata(pdev, keyboard_led);
if (drvdata->init) {
- err = drvdata->init(pdev);
+ err = drvdata->init(pdev, keyboard_led);
if (err)
return err;
}
keyboard_led->cdev.name = "chromeos::kbd_backlight";
keyboard_led->cdev.flags |= LED_CORE_SUSPENDRESUME | LED_REJECT_NAME_CONFLICT;
- keyboard_led->cdev.max_brightness = drvdata->max_brightness;
+ keyboard_led->cdev.max_brightness = 100;
keyboard_led->cdev.brightness_set = drvdata->brightness_set;
keyboard_led->cdev.brightness_set_blocking = drvdata->brightness_set_blocking;
keyboard_led->cdev.brightness_get = drvdata->brightness_get;
diff --git a/drivers/platform/chrome/wilco_ec/event.c b/drivers/platform/chrome/wilco_ec/event.c
index b6e935badc0e9..1b5cb89839e08 100644
--- a/drivers/platform/chrome/wilco_ec/event.c
+++ b/drivers/platform/chrome/wilco_ec/event.c
@@ -452,8 +452,13 @@ static void hangup_device(struct event_device_data *dev_data)
static int event_device_probe(struct platform_device *pdev)
{
struct event_device_data *dev_data;
+ struct acpi_device *adev;
int error, minor;
+ adev = ACPI_COMPANION(&pdev->dev);
+ if (!adev)
+ return -ENODEV;
+
minor = ida_alloc_max(&event_ida, EVENT_MAX_DEV-1, GFP_KERNEL);
if (minor < 0) {
error = minor;
@@ -494,8 +499,7 @@ static int event_device_probe(struct platform_device *pdev)
goto free_dev_data;
/* Install an ACPI notify handler. */
- error = acpi_dev_install_notify_handler(ACPI_COMPANION(&pdev->dev),
- ACPI_DEVICE_NOTIFY,
+ error = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY,
event_device_notify, &pdev->dev);
if (error)
goto free_cdev;