Add support for V4L2 Flash sub-device to the max77693 LED Flash class
driver. The support allows for V4L2 Flash sub-device to take the control
of the LED Flash class device.
Signed-off-by: Jacek Anaszewski j.anaszew...@samsung.com
Acked-by: Kyungmin Park kyungmin.p...@samsung.com
Cc: Bryan Wu coolo...@gmail.com
Cc: Richard Purdie rpur...@rpsys.net
Cc: Sakari Ailus sakari.ai...@iki.fi
---
drivers/leds/leds-max77693.c | 129 --
1 file changed, 123 insertions(+), 6 deletions(-)
diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
index eecaa92..b8b0eec 100644
--- a/drivers/leds/leds-max77693.c
+++ b/drivers/leds/leds-max77693.c
@@ -20,6 +20,7 @@
#include linux/regmap.h
#include linux/slab.h
#include linux/workqueue.h
+#include media/v4l2-flash-led-class.h
#define MODE_OFF 0
#define MODE_FLASH(a) (1 (a))
@@ -62,6 +63,8 @@ struct max77693_sub_led {
struct led_classdev_flash fled_cdev;
/* assures led-triggers compatibility */
struct work_struct work_brightness_set;
+ /* V4L2 Flash device */
+ struct v4l2_flash *v4l2_flash;
/* brightness cache */
unsigned int torch_brightness;
@@ -627,7 +630,8 @@ static int max77693_led_flash_timeout_set(
}
static int max77693_led_parse_dt(struct max77693_led_device *led,
- struct max77693_led_config_data *cfg)
+ struct max77693_led_config_data *cfg,
+ struct device_node **sub_nodes)
{
struct device *dev = led-pdev-dev;
struct max77693_sub_led *sub_leds = led-sub_leds;
@@ -674,6 +678,13 @@ static int max77693_led_parse_dt(struct
max77693_led_device *led,
return -EINVAL;
}
+ if (sub_nodes[fled_id]) {
+ dev_err(dev,
+ Conflicting \led-sources\ DT properties\n);
+ return -EINVAL;
+ }
+
+ sub_nodes[fled_id] = child_node;
sub_leds[fled_id].fled_id = fled_id;
cfg-label[fled_id] =
@@ -786,11 +797,12 @@ static void max77693_led_validate_configuration(struct
max77693_led_device *led,
}
static int max77693_led_get_configuration(struct max77693_led_device *led,
- struct max77693_led_config_data *cfg)
+ struct max77693_led_config_data *cfg,
+ struct device_node **sub_nodes)
{
int ret;
- ret = max77693_led_parse_dt(led, cfg);
+ ret = max77693_led_parse_dt(led, cfg, sub_nodes);
if (ret 0)
return ret;
@@ -838,6 +850,71 @@ static void max77693_init_flash_settings(struct
max77693_sub_led *sub_led,
setting-val = setting-max;
}
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+
+static int max77693_led_external_strobe_set(
+ struct v4l2_flash *v4l2_flash,
+ bool enable)
+{
+ struct max77693_sub_led *sub_led =
+ flcdev_to_sub_led(v4l2_flash-fled_cdev);
+ struct max77693_led_device *led = sub_led_to_led(sub_led);
+ int fled_id = sub_led-fled_id;
+ int ret;
+
+ mutex_lock(led-lock);
+
+ if (enable)
+ ret = max77693_add_mode(led, MODE_FLASH_EXTERNAL(fled_id));
+ else
+ ret = max77693_clear_mode(led, MODE_FLASH_EXTERNAL(fled_id));
+
+ mutex_unlock(led-lock);
+
+ return ret;
+}
+
+static void max77693_init_v4l2_flash_config(struct max77693_sub_led *sub_led,
+ struct max77693_led_config_data *led_cfg,
+ struct v4l2_flash_config *v4l2_sd_cfg)
+{
+ struct max77693_led_device *led = sub_led_to_led(sub_led);
+ struct device *dev = led-pdev-dev;
+ struct max77693_dev *iodev = dev_get_drvdata(dev-parent);
+ struct i2c_client *i2c = iodev-i2c;
+ struct led_flash_setting *s;
+
+ snprintf(v4l2_sd_cfg-dev_name, sizeof(v4l2_sd_cfg-dev_name),
+%s %d-%04x, sub_led-fled_cdev.led_cdev.name,
+i2c_adapter_id(i2c-adapter), i2c-addr);
+
+ s = v4l2_sd_cfg-torch_intensity;
+ s-min = TORCH_IOUT_MIN;
+ s-max = sub_led-fled_cdev.led_cdev.max_brightness * TORCH_IOUT_STEP;
+ s-step = TORCH_IOUT_STEP;
+ s-val = s-max;
+
+ /* Init flash faults config */
+ v4l2_sd_cfg-flash_faults = LED_FAULT_OVER_VOLTAGE |
+ LED_FAULT_SHORT_CIRCUIT |
+ LED_FAULT_OVER_CURRENT;
+
+ v4l2_sd_cfg-has_external_strobe = true;
+}
+
+static const struct v4l2_flash_ops v4l2_flash_ops = {
+ .external_strobe_set = max77693_led_external_strobe_set,
+};
+#else
+static inline void max77693_init_v4l2_flash_config(
+ struct