{
struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c);
struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
- struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+ struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
bool external_strobe;
int ret = 0;
struct v4l2_flash_ctrl_data *ctrl_init_data)
{
struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
- struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+ struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
struct v4l2_ctrl_config *ctrl_cfg;
u32 mask;
+ /* Init INDICATOR_INTENSITY ctrl data */
+ if (v4l2_flash->iled_cdev) {
+ ctrl_init_data[INDICATOR_INTENSITY].cid =
+ V4L2_CID_FLASH_INDICATOR_INTENSITY;
+ ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config;
+ __lfs_to_v4l2_ctrl_config(&flash_cfg->intensity,
+ ctrl_cfg);
+ ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
+ ctrl_cfg->min = 0;
+ ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
+ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+ }
+
+ if (!led_cdev || WARN_ON(!(led_cdev->flags & LED_DEV_CAP_FLASH)))
+ return;
+
/* Init FLASH_FAULT ctrl data */
if (flash_cfg->flash_faults) {
ctrl_init_data[FLASH_FAULT].cid = V4L2_CID_FLASH_FAULT;
/* Init TORCH_INTENSITY ctrl data */
ctrl_init_data[TORCH_INTENSITY].cid = V4L2_CID_FLASH_TORCH_INTENSITY;
ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config;
- __lfs_to_v4l2_ctrl_config(&flash_cfg->torch_intensity, ctrl_cfg);
+ __lfs_to_v4l2_ctrl_config(&flash_cfg->intensity, ctrl_cfg);
ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY;
ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
- /* Init INDICATOR_INTENSITY ctrl data */
- if (v4l2_flash->iled_cdev) {
- ctrl_init_data[INDICATOR_INTENSITY].cid =
- V4L2_CID_FLASH_INDICATOR_INTENSITY;
- ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config;
- __lfs_to_v4l2_ctrl_config(&flash_cfg->indicator_intensity,
- ctrl_cfg);
- ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
- ctrl_cfg->min = 0;
- ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
- V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
- }
-
- if (!(led_cdev->flags & LED_DEV_CAP_FLASH))
- return;
-
/* Init FLASH_STROBE ctrl data */
ctrl_init_data[FLASH_STROBE].cid = V4L2_CID_FLASH_STROBE;
ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config;
struct v4l2_ctrl **ctrls = v4l2_flash->ctrls;
int ret = 0;
- v4l2_flash_set_led_brightness(v4l2_flash, ctrls[TORCH_INTENSITY]);
+ if (ctrls[TORCH_INTENSITY])
+ v4l2_flash_set_led_brightness(v4l2_flash,
+ ctrls[TORCH_INTENSITY]);
if (ctrls[INDICATOR_INTENSITY])
v4l2_flash_set_led_brightness(v4l2_flash,
{
struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd);
struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
- struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+ struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev;
int ret = 0;
if (!v4l2_fh_is_singular(&fh->vfh))
return 0;
- mutex_lock(&led_cdev->led_access);
+ if (led_cdev) {
+ mutex_lock(&led_cdev->led_access);
- led_sysfs_disable(led_cdev);
- led_trigger_remove(led_cdev);
+ led_sysfs_disable(led_cdev);
+ led_trigger_remove(led_cdev);
- mutex_unlock(&led_cdev->led_access);
+ mutex_unlock(&led_cdev->led_access);
+ }
if (led_cdev_ind) {
mutex_lock(&led_cdev_ind->led_access);
return 0;
out_sync_device:
- mutex_lock(&led_cdev->led_access);
- led_sysfs_enable(led_cdev);
- mutex_unlock(&led_cdev->led_access);
+ if (led_cdev) {
+ mutex_lock(&led_cdev->led_access);
+ led_sysfs_enable(led_cdev);
+ mutex_unlock(&led_cdev->led_access);
+ }
if (led_cdev_ind) {
mutex_lock(&led_cdev_ind->led_access);
{
struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd);
struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
- struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+ struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL;
struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev;
int ret = 0;
if (!v4l2_fh_is_singular(&fh->vfh))
return 0;
- mutex_lock(&led_cdev->led_access);
+ if (led_cdev) {
+ mutex_lock(&led_cdev->led_access);
- if (v4l2_flash->ctrls[STROBE_SOURCE])
- ret = v4l2_ctrl_s_ctrl(v4l2_flash->ctrls[STROBE_SOURCE],
+ if (v4l2_flash->ctrls[STROBE_SOURCE])
+ ret = v4l2_ctrl_s_ctrl(
+ v4l2_flash->ctrls[STROBE_SOURCE],
V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
- led_sysfs_enable(led_cdev);
+ led_sysfs_enable(led_cdev);
- mutex_unlock(&led_cdev->led_access);
+ mutex_unlock(&led_cdev->led_access);
+ }
if (led_cdev_ind) {
mutex_lock(&led_cdev_ind->led_access);
static const struct v4l2_subdev_ops v4l2_flash_subdev_ops;
-struct v4l2_flash *v4l2_flash_init(
+static struct v4l2_flash *__v4l2_flash_init(
struct device *dev, struct fwnode_handle *fwn,
- struct led_classdev_flash *fled_cdev,
- struct led_classdev *iled_cdev,
- const struct v4l2_flash_ops *ops,
- struct v4l2_flash_config *config)
+ struct led_classdev_flash *fled_cdev, struct led_classdev *iled_cdev,
+ const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config)
{
struct v4l2_flash *v4l2_flash;
- struct led_classdev *led_cdev;
struct v4l2_subdev *sd;
int ret;
- if (!fled_cdev || !config)
+ if (!config)
return ERR_PTR(-EINVAL);
- led_cdev = &fled_cdev->led_cdev;
-
- v4l2_flash = devm_kzalloc(led_cdev->dev, sizeof(*v4l2_flash),
- GFP_KERNEL);
+ v4l2_flash = devm_kzalloc(dev, sizeof(*v4l2_flash), GFP_KERNEL);
if (!v4l2_flash)
return ERR_PTR(-ENOMEM);
v4l2_flash->iled_cdev = iled_cdev;
v4l2_flash->ops = ops;
sd->dev = dev;
- sd->fwnode = fwn ? fwn : dev_fwnode(led_cdev->dev);
+ sd->fwnode = fwn ? fwn : dev_fwnode(dev);
v4l2_subdev_init(sd, &v4l2_flash_subdev_ops);
sd->internal_ops = &v4l2_flash_subdev_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
return ERR_PTR(ret);
}
+
+struct v4l2_flash *v4l2_flash_init(
+ struct device *dev, struct fwnode_handle *fwn,
+ struct led_classdev_flash *fled_cdev,
+ const struct v4l2_flash_ops *ops,
+ struct v4l2_flash_config *config)
+{
+ return __v4l2_flash_init(dev, fwn, fled_cdev, NULL, ops, config);
+}
EXPORT_SYMBOL_GPL(v4l2_flash_init);
+struct v4l2_flash *v4l2_flash_indicator_init(
+ struct device *dev, struct fwnode_handle *fwn,
+ struct led_classdev *iled_cdev,
+ struct v4l2_flash_config *config)
+{
+ return __v4l2_flash_init(dev, fwn, NULL, iled_cdev, NULL, config);
+}
+EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init);
+
void v4l2_flash_release(struct v4l2_flash *v4l2_flash)
{
struct v4l2_subdev *sd;
bool ready;
#if IS_REACHABLE(CONFIG_V4L2_FLASH_LED_CLASS)
struct v4l2_flash *v4l2_flash;
+ struct v4l2_flash *v4l2_flash_ind;
#endif
};
{
struct gb_connection *connection = get_conn_from_light(light);
struct device *dev = &connection->bundle->dev;
- struct v4l2_flash_config sd_cfg = { {0} };
+ struct v4l2_flash_config sd_cfg = { {0} }, sd_cfg_ind = { {0} };
struct led_classdev_flash *fled;
struct led_classdev *iled = NULL;
struct gb_channel *channel_torch, *channel_ind, *channel_flash;
channel_torch = get_channel_from_mode(light, GB_CHANNEL_MODE_TORCH);
if (channel_torch)
__gb_lights_channel_v4l2_config(&channel_torch->intensity_uA,
- &sd_cfg.torch_intensity);
+ &sd_cfg.intensity);
channel_ind = get_channel_from_mode(light, GB_CHANNEL_MODE_INDICATOR);
if (channel_ind) {
__gb_lights_channel_v4l2_config(&channel_ind->intensity_uA,
- &sd_cfg.indicator_intensity);
+ &sd_cfg_ind.intensity);
iled = &channel_ind->fled.led_cdev;
}
fled = &channel_flash->fled;
snprintf(sd_cfg.dev_name, sizeof(sd_cfg.dev_name), "%s", light->name);
+ snprintf(sd_cfg_ind.dev_name, sizeof(sd_cfg_ind.dev_name),
+ "%s indicator", light->name);
/* Set the possible values to faults, in our case all faults */
sd_cfg.flash_faults = LED_FAULT_OVER_VOLTAGE | LED_FAULT_TIMEOUT |
LED_FAULT_UNDER_VOLTAGE | LED_FAULT_INPUT_VOLTAGE |
LED_FAULT_LED_OVER_TEMPERATURE;
- light->v4l2_flash = v4l2_flash_init(dev, NULL, fled, iled,
- &v4l2_flash_ops, &sd_cfg);
+ light->v4l2_flash = v4l2_flash_init(dev, NULL, fled, &v4l2_flash_ops,
+ &sd_cfg);
if (IS_ERR(light->v4l2_flash))
return PTR_ERR(light->v4l2_flash);
+ if (channel_ind) {
+ light->v4l2_flash_ind =
+ v4l2_flash_indicator_init(dev, NULL, iled, &sd_cfg_ind);
+ if (IS_ERR(light->v4l2_flash_ind)) {
+ v4l2_flash_release(light->v4l2_flash);
+ return PTR_ERR(light->v4l2_flash_ind);
+ }
+ }
+
return 0;
}
static void gb_lights_light_v4l2_unregister(struct gb_light *light)
{
+ v4l2_flash_release(light->v4l2_flash_ind);
v4l2_flash_release(light->v4l2_flash);
}
#else
* struct v4l2_flash_config - V4L2 Flash sub-device initialization data
* @dev_name: the name of the media entity,
* unique in the system
- * @torch_intensity: constraints for the LED in torch mode
- * @indicator_intensity: constraints for the indicator LED
+ * @intensity: non-flash strobe constraints for the LED
* @flash_faults: bitmask of flash faults that the LED flash class
* device can report; corresponding LED_FAULT* bit
* definitions are available in the header file
*/
struct v4l2_flash_config {
char dev_name[32];
- struct led_flash_setting torch_intensity;
- struct led_flash_setting indicator_intensity;
+ struct led_flash_setting intensity;
u32 flash_faults;
unsigned int has_external_strobe:1;
};
* @dev: flash device, e.g. an I2C device
* @fwn: fwnode_handle of the LED, may be NULL if the same as device's
* @fled_cdev: LED flash class device to wrap
- * @iled_cdev: LED flash class device representing indicator LED associated
- * with fled_cdev, may be NULL
* @ops: V4L2 Flash device ops
* @config: initialization data for V4L2 Flash sub-device
*
struct v4l2_flash *v4l2_flash_init(
struct device *dev, struct fwnode_handle *fwn,
struct led_classdev_flash *fled_cdev,
- struct led_classdev *iled_cdev,
- const struct v4l2_flash_ops *ops,
- struct v4l2_flash_config *config);
+ const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config);
+
+/**
+ * v4l2_flash_indicator_init - initialize V4L2 indicator sub-device
+ * @dev: flash device, e.g. an I2C device
+ * @fwn: fwnode_handle of the LED, may be NULL if the same as device's
+ * @iled_cdev: LED flash class device representing the indicator LED
+ * @config: initialization data for V4L2 Flash sub-device
+ *
+ * Create V4L2 Flash sub-device wrapping given LED subsystem device.
+ *
+ * Returns: A valid pointer, or, when an error occurs, the return
+ * value is encoded using ERR_PTR(). Use IS_ERR() to check and
+ * PTR_ERR() to obtain the numeric return value.
+ */
+struct v4l2_flash *v4l2_flash_indicator_init(
+ struct device *dev, struct fwnode_handle *fwn,
+ struct led_classdev *iled_cdev, struct v4l2_flash_config *config);
/**
* v4l2_flash_release - release V4L2 Flash sub-device
static inline struct v4l2_flash *v4l2_flash_init(
struct device *dev, struct fwnode_handle *fwn,
struct led_classdev_flash *fled_cdev,
- struct led_classdev *iled_cdev,
- const struct v4l2_flash_ops *ops,
- struct v4l2_flash_config *config)
+ const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config)
+{
+ return NULL;
+}
+
+static inline struct v4l2_flash *v4l2_flash_indicator_init(
+ struct device *dev, struct fwnode_handle *fwn,
+ struct led_classdev *iled_cdev, struct v4l2_flash_config *config)
{
return NULL;
}