All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jacek Anaszewski <j.anaszewski@samsung.com>
To: linux-leds@vger.kernel.org, linux-media@vger.kernel.org
Cc: kyungmin.park@samsung.com, pavel@ucw.cz, cooloney@gmail.com,
	rpurdie@rpsys.net, sakari.ailus@iki.fi, s.nawrocki@samsung.com,
	Jacek Anaszewski <j.anaszewski@samsung.com>
Subject: [PATCH v5 08/10] leds: max77693: add support for V4L2 Flash sub-device
Date: Wed, 15 Apr 2015 08:48:38 +0200	[thread overview]
Message-ID: <1429080520-10687-9-git-send-email-j.anaszewski@samsung.com> (raw)
In-Reply-To: <1429080520-10687-1-git-send-email-j.anaszewski@samsung.com>

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.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Bryan Wu <cooloney@gmail.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: Sakari Ailus <sakari.ailus@iki.fi>
---
 drivers/leds/leds-max77693.c |  128 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 122 insertions(+), 6 deletions(-)

diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
index d2b9611..52a66f4 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.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;
@@ -634,7 +637,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;
@@ -679,6 +683,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] =
@@ -789,11 +800,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;
 
@@ -841,6 +853,66 @@ 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->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
+#define max77693_init_v4l2_flash_config(sub_led, led_cfg, v4l2_sd_cfg)
+#endif
+
 static void max77693_init_fled_cdev(struct max77693_sub_led *sub_led,
 				struct max77693_led_config_data *led_cfg)
 {
@@ -873,12 +945,49 @@ static void max77693_init_fled_cdev(struct max77693_sub_led *sub_led,
 	sub_led->flash_timeout = fled_cdev->timeout.val;
 }
 
+static int max77693_register_led(struct max77693_sub_led *sub_led,
+				 struct max77693_led_config_data *led_cfg,
+				 struct device_node *sub_node)
+{
+	struct max77693_led_device *led = sub_led_to_led(sub_led);
+	struct led_classdev_flash *fled_cdev = &sub_led->fled_cdev;
+	struct device *dev = &led->pdev->dev;
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+	struct v4l2_flash_config v4l2_sd_cfg = {};
+#endif
+	int ret;
+
+	/* Register in the LED subsystem */
+	ret = led_classdev_flash_register(dev, fled_cdev);
+	if (ret < 0)
+		return ret;
+
+	max77693_init_v4l2_flash_config(sub_led, led_cfg, &v4l2_sd_cfg);
+
+	fled_cdev->led_cdev.dev->of_node = sub_node;
+
+	/* Register in the V4L2 subsystem. */
+	sub_led->v4l2_flash = v4l2_flash_init(fled_cdev, &v4l2_flash_ops,
+						&v4l2_sd_cfg);
+	if (IS_ERR(sub_led->v4l2_flash)) {
+		ret = PTR_ERR(sub_led->v4l2_flash);
+		goto err_v4l2_flash_init;
+	}
+
+	return 0;
+
+err_v4l2_flash_init:
+	led_classdev_flash_unregister(fled_cdev);
+	return ret;
+}
+
 static int max77693_led_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct max77693_dev *iodev = dev_get_drvdata(dev->parent);
 	struct max77693_led_device *led;
 	struct max77693_sub_led *sub_leds;
+	struct device_node *sub_nodes[2] = {};
 	struct max77693_led_config_data led_cfg = {};
 	int init_fled_cdev[2], i, ret;
 
@@ -892,7 +1001,7 @@ static int max77693_led_probe(struct platform_device *pdev)
 	sub_leds = led->sub_leds;
 
 	platform_set_drvdata(pdev, led);
-	ret = max77693_led_get_configuration(led, &led_cfg);
+	ret = max77693_led_get_configuration(led, &led_cfg, sub_nodes);
 	if (ret < 0)
 		return ret;
 
@@ -914,8 +1023,12 @@ static int max77693_led_probe(struct platform_device *pdev)
 		/* Initialize LED Flash class device */
 		max77693_init_fled_cdev(&sub_leds[i], &led_cfg);
 
-		/* Register LED Flash class device */
-		ret = led_classdev_flash_register(dev, &sub_leds[i].fled_cdev);
+		/*
+		 * Register LED Flash class device and corresponding
+		 * V4L2 Flash device.
+		 */
+		ret = max77693_register_led(&sub_leds[i], &led_cfg,
+						sub_nodes[i]);
 		if (ret < 0) {
 			/*
 			 * At this moment FLED1 might have been already
@@ -934,6 +1047,7 @@ err_register_led2:
 	/* It is possible than only FLED2 was to be registered */
 	if (!init_fled_cdev[FLED1])
 		goto err_register_led1;
+	v4l2_flash_release(sub_leds[FLED1].v4l2_flash);
 	led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
 err_register_led1:
 	mutex_destroy(&led->lock);
@@ -947,11 +1061,13 @@ static int max77693_led_remove(struct platform_device *pdev)
 	struct max77693_sub_led *sub_leds = led->sub_leds;
 
 	if (led->iout_joint || max77693_fled_used(led, FLED1)) {
+		v4l2_flash_release(sub_leds[FLED1].v4l2_flash);
 		led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
 		cancel_work_sync(&sub_leds[FLED1].work_brightness_set);
 	}
 
 	if (!led->iout_joint && max77693_fled_used(led, FLED2)) {
+		v4l2_flash_release(sub_leds[FLED2].v4l2_flash);
 		led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);
 		cancel_work_sync(&sub_leds[FLED2].work_brightness_set);
 	}
-- 
1.7.9.5

  parent reply	other threads:[~2015-04-15  6:49 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-15  6:48 [PATCH v5 00/10] LED / flash API integration Jacek Anaszewski
2015-04-15  6:48 ` [PATCH v5 01/10] leds: unify the location of led-trigger API Jacek Anaszewski
2015-04-15  8:32   ` Sakari Ailus
     [not found] ` <1429080520-10687-1-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-04-15  6:48   ` [PATCH v5 02/10] DT: Add documentation for the mfd Maxim max77693 Jacek Anaszewski
2015-04-15  6:48     ` Jacek Anaszewski
2015-04-15  8:33     ` Sakari Ailus
2015-04-29 12:34     ` Lee Jones
2015-04-29 12:59       ` Jacek Anaszewski
2015-04-29 13:16         ` Lee Jones
2015-04-15  6:48 ` [PATCH v5 03/10] leds: Add support for max77693 mfd flash cell Jacek Anaszewski
2015-04-15  9:30   ` Sakari Ailus
2015-04-15 14:07     ` Jacek Anaszewski
2015-04-15  6:48 ` [PATCH v5 04/10] DT: Add documentation for the Skyworks AAT1290 Jacek Anaszewski
     [not found]   ` <1429080520-10687-5-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-04-19 12:05     ` Sakari Ailus
2015-04-19 12:05       ` Sakari Ailus
2015-04-15  6:48 ` [PATCH v5 05/10] leds: Add driver for AAT1290 flash LED controller Jacek Anaszewski
2015-04-15  6:48 ` [PATCH v5 06/10] media: Add registration helpers for V4L2 flash sub-devices Jacek Anaszewski
2015-04-23  7:40   ` Sakari Ailus
2015-04-23 15:10     ` Jacek Anaszewski
2015-04-23 15:10       ` Jacek Anaszewski
2015-04-23 21:52       ` Sakari Ailus
2015-04-24 10:29         ` Jacek Anaszewski
2015-04-24 11:56           ` Sakari Ailus
2015-04-15  6:48 ` [PATCH v5 07/10] Documentation: leds: Add description of v4l2-flash sub-device Jacek Anaszewski
2015-04-15  6:48 ` Jacek Anaszewski [this message]
2015-04-15  6:48 ` [PATCH v5 09/10] DT: aat1290: Document handling external strobe sources Jacek Anaszewski
2015-04-15  6:48 ` [PATCH v5 10/10] leds: aat1290: add support for V4L2 Flash sub-device Jacek Anaszewski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1429080520-10687-9-git-send-email-j.anaszewski@samsung.com \
    --to=j.anaszewski@samsung.com \
    --cc=cooloney@gmail.com \
    --cc=kyungmin.park@samsung.com \
    --cc=linux-leds@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=pavel@ucw.cz \
    --cc=rpurdie@rpsys.net \
    --cc=s.nawrocki@samsung.com \
    --cc=sakari.ailus@iki.fi \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.