media: v4l2-core: Make the v4l2-core code enable/disable the privacy LED if present
Make v4l2_async_register_subdev_sensor() try to get a privacy LED associated with the sensor and extend the call_s_stream() wrapper to enable/disable the privacy LED if found. This makes the core handle privacy LED control, rather then having to duplicate this code in all the sensor drivers. Suggested-by: Sakari Ailus <sakari.ailus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com> Link: https://lore.kernel.org/r/20230127203729.10205-2-hdegoede@redhat.com
This commit is contained in:
parent
39f0932050
commit
b6e10ff6c2
|
@ -24,6 +24,8 @@
|
|||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "v4l2-subdev-priv.h"
|
||||
|
||||
static int v4l2_async_nf_call_bound(struct v4l2_async_notifier *n,
|
||||
struct v4l2_subdev *subdev,
|
||||
struct v4l2_async_subdev *asd)
|
||||
|
@ -822,6 +824,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
|
|||
if (!sd->async_list.next)
|
||||
return;
|
||||
|
||||
v4l2_subdev_put_privacy_led(sd);
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
__v4l2_async_nf_unregister(sd->subdev_notifier);
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "v4l2-subdev-priv.h"
|
||||
|
||||
static const struct v4l2_fwnode_bus_conv {
|
||||
enum v4l2_fwnode_bus_type fwnode_bus_type;
|
||||
enum v4l2_mbus_type mbus_type;
|
||||
|
@ -1302,6 +1304,10 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
|
|||
|
||||
v4l2_async_nf_init(notifier);
|
||||
|
||||
ret = v4l2_subdev_get_privacy_led(sd);
|
||||
if (ret < 0)
|
||||
goto out_cleanup;
|
||||
|
||||
ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier);
|
||||
if (ret < 0)
|
||||
goto out_cleanup;
|
||||
|
@ -1322,6 +1328,7 @@ out_unregister:
|
|||
v4l2_async_nf_unregister(notifier);
|
||||
|
||||
out_cleanup:
|
||||
v4l2_subdev_put_privacy_led(sd);
|
||||
v4l2_async_nf_cleanup(notifier);
|
||||
kfree(notifier);
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* V4L2 sub-device pivate header.
|
||||
*
|
||||
* Copyright (C) 2023 Hans de Goede <hdegoede@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef _V4L2_SUBDEV_PRIV_H_
|
||||
#define _V4L2_SUBDEV_PRIV_H_
|
||||
|
||||
int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd);
|
||||
void v4l2_subdev_put_privacy_led(struct v4l2_subdev *sd);
|
||||
|
||||
#endif
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -23,6 +24,8 @@
|
|||
#include <media/v4l2-fh.h>
|
||||
#include <media/v4l2-event.h>
|
||||
|
||||
#include "v4l2-subdev-priv.h"
|
||||
|
||||
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
|
||||
static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
|
||||
{
|
||||
|
@ -322,6 +325,15 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable)
|
|||
{
|
||||
int ret;
|
||||
|
||||
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
|
||||
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
|
||||
if (enable)
|
||||
led_set_brightness(sd->privacy_led,
|
||||
sd->privacy_led->max_brightness);
|
||||
else
|
||||
led_set_brightness(sd->privacy_led, 0);
|
||||
}
|
||||
#endif
|
||||
ret = sd->ops->video->s_stream(sd, enable);
|
||||
|
||||
if (!enable && ret < 0) {
|
||||
|
@ -1090,6 +1102,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
|
|||
sd->grp_id = 0;
|
||||
sd->dev_priv = NULL;
|
||||
sd->host_priv = NULL;
|
||||
sd->privacy_led = NULL;
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
sd->entity.name = sd->name;
|
||||
sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV;
|
||||
|
@ -1105,3 +1118,36 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd,
|
|||
v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, (void *)ev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event);
|
||||
|
||||
int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd)
|
||||
{
|
||||
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
|
||||
sd->privacy_led = led_get(sd->dev, "privacy-led");
|
||||
if (IS_ERR(sd->privacy_led) && PTR_ERR(sd->privacy_led) != -ENOENT)
|
||||
return dev_err_probe(sd->dev, PTR_ERR(sd->privacy_led),
|
||||
"getting privacy LED\n");
|
||||
|
||||
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
|
||||
mutex_lock(&sd->privacy_led->led_access);
|
||||
led_sysfs_disable(sd->privacy_led);
|
||||
led_trigger_remove(sd->privacy_led);
|
||||
led_set_brightness(sd->privacy_led, 0);
|
||||
mutex_unlock(&sd->privacy_led->led_access);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_subdev_get_privacy_led);
|
||||
|
||||
void v4l2_subdev_put_privacy_led(struct v4l2_subdev *sd)
|
||||
{
|
||||
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
|
||||
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
|
||||
mutex_lock(&sd->privacy_led->led_access);
|
||||
led_sysfs_enable(sd->privacy_led);
|
||||
mutex_unlock(&sd->privacy_led->led_access);
|
||||
led_put(sd->privacy_led);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_subdev_put_privacy_led);
|
||||
|
|
|
@ -38,6 +38,7 @@ struct v4l2_subdev;
|
|||
struct v4l2_subdev_fh;
|
||||
struct tuner_setup;
|
||||
struct v4l2_mbus_frame_desc;
|
||||
struct led_classdev;
|
||||
|
||||
/**
|
||||
* struct v4l2_decode_vbi_line - used to decode_vbi_line
|
||||
|
@ -941,6 +942,7 @@ struct v4l2_subdev_platform_data {
|
|||
* @state_lock: A pointer to a lock used for all the subdev's states, set by the
|
||||
* driver. This is optional. If NULL, each state instance will get
|
||||
* a lock of its own.
|
||||
* @privacy_led: Optional pointer to a LED classdev for the privacy LED for sensors.
|
||||
* @active_state: Active state for the subdev (NULL for subdevs tracking the
|
||||
* state internally). Initialized by calling
|
||||
* v4l2_subdev_init_finalize().
|
||||
|
@ -982,6 +984,8 @@ struct v4l2_subdev {
|
|||
* appropriate functions.
|
||||
*/
|
||||
|
||||
struct led_classdev *privacy_led;
|
||||
|
||||
/*
|
||||
* TODO: active_state should most likely be changed from a pointer to an
|
||||
* embedded field. For the time being it's kept as a pointer to more
|
||||
|
|
Loading…
Reference in New Issue