All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH/RFC v10 00/19] LED / flash API integration
@ 2015-01-09 15:22 Jacek Anaszewski
  2015-01-09 15:22 ` [PATCH/RFC v10 01/19] leds: Add LED Flash class extension to the LED subsystem Jacek Anaszewski
                   ` (18 more replies)
  0 siblings, 19 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski

This patch set is a follow-up of the LED / flash API integration
series [1]. It is based on linux-next_20150108.

========================
Changes since version 9 :
========================

- switched to assigning sub-led related of_node to led_cdev->dev->of_node
  member which allowed for avoiding modifications around v4l-async
- reimplemented max77693 flash cell driver to avoid extensive use
  of macros
- added led-sources DT property and switched to using it
- switched to reporting flash faults in the LED subsystem in the form
  of human readable strings
- added available_sync_leds sysfs attribute to the LED Flash class
  and changed the semantics of flash_sync_strobe attribute
- made LED subsystem flash faults not depending on the V4L2 Flash ones
- applied various fixes and cleanups

========================
Changes since version 8:
========================

- added a new way of registering async sub-device
- switched to matching flash leds by DT phandles
- improved Device Tree bindings documentation
- split the drivers patches to LED Flash class
  and V4L2 Flash part
- fixed indicator leds handling in v4l2-flash
- applied various fixes an cleanups

========================
Changes since version 7:
========================

- removed explicit support for indicator leds from
  LED Flash class - indicator leds will be registered
  as a separate LED Flash class devices
- added flash_sync_strobe sysfs attribute and related
  V4L2_CID_FLASH_SYNC_STROBE control
- changed the way of matching V4L2 Flash sub-devices
  in a media device, which entailed modification in
  v4l2-async driver
- modified max77693 DT bindings documentation
- applied various fixes an cleanups

========================
Changes since version 6:
========================

- removed addition of public LED subsystem API for setting
  torch brightness in favour of internal API for
  synchronous and asynchronous led brightness level setting
- fixed possible race condition upon creating LED Flash class
  related sysfs attributes

========================
Changes since version 5:
========================

- removed flash manager framework - its implementation needs
  further thorough discussion.
- removed external strobe facilities from the LED Flash Class
  and provided external_strobe_set op in v4l2-flash. LED subsystem
  should be strobe provider agnostic.

Thanks,
Jacek Anaszewski

[1] https://lkml.org/lkml/2014/7/11/914

Jacek Anaszewski (19):
  leds: Add LED Flash class extension to the LED subsystem
  Documentation: leds: Add description of LED Flash class extension
  DT: leds: Add led-sources property
  dt-binding: mfd: max77693: Add DT binding related macros
  mfd: max77693: Modify flash cell name identifiers
  mfd: max77693: modifications around max77693_led_platform_data
  mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros
  leds: Add support for max77693 mfd flash cell
  DT: Add documentation for the mfd Maxim max77693
  leds: Add driver for AAT1290 current regulator
  of: Add Skyworks Solutions, Inc. vendor prefix
  DT: Add documentation for the Skyworks AAT1290
  exynos4-is: Add support for v4l2-flash subdevs
  v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control
  media: Add registration helpers for V4L2 flash sub-devices
  Documentation: leds: Add description of v4l2-flash sub-device
  DT: Add documentation for exynos4-is 'flashes' property
  leds: max77693: add support for V4L2 Flash sub-device
  leds: aat1290: add support for V4L2 Flash sub-device

 Documentation/DocBook/media/v4l/controls.xml       |    9 +
 Documentation/devicetree/bindings/leds/common.txt  |    5 +
 .../devicetree/bindings/leds/leds-aat1290.txt      |   17 +
 .../devicetree/bindings/media/samsung-fimc.txt     |    7 +
 Documentation/devicetree/bindings/mfd/max77693.txt |   69 ++
 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 Documentation/leds/leds-class-flash.txt            |   70 ++
 drivers/leds/Kconfig                               |   27 +
 drivers/leds/Makefile                              |    3 +
 drivers/leds/led-class-flash.c                     |  486 ++++++++
 drivers/leds/led-class.c                           |    4 +
 drivers/leds/leds-aat1290.c                        |  460 ++++++++
 drivers/leds/leds-max77693.c                       | 1178 ++++++++++++++++++++
 drivers/media/platform/exynos4-is/media-dev.c      |   36 +-
 drivers/media/platform/exynos4-is/media-dev.h      |   13 +-
 drivers/media/v4l2-core/Kconfig                    |   11 +
 drivers/media/v4l2-core/Makefile                   |    2 +
 drivers/media/v4l2-core/v4l2-ctrls.c               |    2 +
 drivers/media/v4l2-core/v4l2-flash.c               |  581 ++++++++++
 drivers/mfd/max77693.c                             |    4 +-
 include/dt-bindings/mfd/max77693.h                 |   21 +
 include/linux/led-class-flash.h                    |  207 ++++
 include/linux/leds.h                               |    3 +
 include/linux/mfd/max77693-private.h               |    4 +-
 include/linux/mfd/max77693.h                       |    9 +-
 include/media/v4l2-flash.h                         |  139 +++
 include/uapi/linux/v4l2-controls.h                 |    1 +
 27 files changed, 3357 insertions(+), 12 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-aat1290.txt
 create mode 100644 Documentation/leds/leds-class-flash.txt
 create mode 100644 drivers/leds/led-class-flash.c
 create mode 100644 drivers/leds/leds-aat1290.c
 create mode 100644 drivers/leds/leds-max77693.c
 create mode 100644 drivers/media/v4l2-core/v4l2-flash.c
 create mode 100644 include/dt-bindings/mfd/max77693.h
 create mode 100644 include/linux/led-class-flash.h
 create mode 100644 include/media/v4l2-flash.h

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 01/19] leds: Add LED Flash class extension to the LED subsystem
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
@ 2015-01-09 15:22 ` Jacek Anaszewski
  2015-01-09 17:37   ` Pavel Machek
  2015-01-09 15:22 ` [PATCH/RFC v10 02/19] Documentation: leds: Add description of LED Flash class extension Jacek Anaszewski
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski

Some LED devices support two operation modes - torch and flash.
This patch provides support for flash LED devices in the LED subsystem
by introducing new sysfs attributes and kernel internal interface.
The attributes being introduced are: flash_brightness, flash_strobe,
flash_timeout, max_flash_timeout, max_flash_brightness, flash_fault,
flash_sync_strobe and available_sync_leds. All the flash related
features are placed in a separate module.

The modifications aim to be compatible with V4L2 framework requirements
related to the flash devices management. The design assumes that V4L2
sub-device can take of the LED class device control and communicate
with it through the kernel internal interface. When V4L2 Flash sub-device
file is opened, the LED class device sysfs interface is made
unavailable.

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>
---
 drivers/leds/Kconfig            |   10 +
 drivers/leds/Makefile           |    1 +
 drivers/leds/led-class-flash.c  |  486 +++++++++++++++++++++++++++++++++++++++
 drivers/leds/led-class.c        |    4 +
 include/linux/led-class-flash.h |  207 +++++++++++++++++
 include/linux/leds.h            |    3 +
 6 files changed, 711 insertions(+)
 create mode 100644 drivers/leds/led-class-flash.c
 create mode 100644 include/linux/led-class-flash.h

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 59f4228..95029df 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -19,6 +19,16 @@ config LEDS_CLASS
 	  This option enables the led sysfs class in /sys/class/leds.  You'll
 	  need this to do anything useful with LEDs.  If unsure, say N.
 
+config LEDS_CLASS_FLASH
+	tristate "LED Flash Class Support"
+	depends on LEDS_CLASS
+	help
+	  This option enables the flash led sysfs class in /sys/class/leds.
+	  It wrapps LED Class and adds flash LEDs specific sysfs attributes
+	  and kernel internal API to it. You'll need this to provide support
+	  for the flash related features of a LED device. It can be built
+	  as a module.
+
 comment "LED drivers"
 
 config LEDS_88PM860X
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 1c65a19..cbba921 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -2,6 +2,7 @@
 # LED Core
 obj-$(CONFIG_NEW_LEDS)			+= led-core.o
 obj-$(CONFIG_LEDS_CLASS)		+= led-class.o
+obj-$(CONFIG_LEDS_CLASS_FLASH)		+= led-class-flash.o
 obj-$(CONFIG_LEDS_TRIGGERS)		+= led-triggers.o
 
 # LED Platform Drivers
diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
new file mode 100644
index 0000000..4a19fd4
--- /dev/null
+++ b/drivers/leds/led-class-flash.c
@@ -0,0 +1,486 @@
+/*
+ * LED Flash class interface
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/led-class-flash.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "leds.h"
+
+#define has_flash_op(fled_cdev, op)				\
+	(fled_cdev && fled_cdev->ops->op)
+
+#define call_flash_op(fled_cdev, op, args...)		\
+	((has_flash_op(fled_cdev, op)) ?			\
+			(fled_cdev->ops->op(fled_cdev, args)) :	\
+			-EINVAL)
+
+static const char * const led_flash_fault_names[] = {
+	"led-over-voltage",
+	"flash-timeout-exceeded",
+	"controller-over-temperature",
+	"controller-short-circuit",
+	"led-power-supply-over-current",
+	"indicator-led-fault",
+	"led-under-voltage",
+	"controller-under-voltage",
+	"led-over-temperature",
+};
+
+static ssize_t flash_brightness_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	unsigned long state;
+	ssize_t ret;
+
+	mutex_lock(&led_cdev->led_access);
+
+	if (led_sysfs_is_disabled(led_cdev)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	ret = kstrtoul(buf, 10, &state);
+	if (ret)
+		goto unlock;
+
+	ret = led_set_flash_brightness(fled_cdev, state);
+	if (ret < 0)
+		goto unlock;
+
+	ret = size;
+unlock:
+	mutex_unlock(&led_cdev->led_access);
+	return ret;
+}
+
+static ssize_t flash_brightness_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+	/* no lock needed for this */
+	led_update_flash_brightness(fled_cdev);
+
+	return sprintf(buf, "%u\n", fled_cdev->brightness.val);
+}
+static DEVICE_ATTR_RW(flash_brightness);
+
+static ssize_t max_flash_brightness_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+	return sprintf(buf, "%u\n", fled_cdev->brightness.max);
+}
+static DEVICE_ATTR_RO(max_flash_brightness);
+
+static ssize_t flash_strobe_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	unsigned long state;
+	ssize_t ret = -EINVAL;
+
+	mutex_lock(&led_cdev->led_access);
+
+	if (led_sysfs_is_disabled(led_cdev)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	ret = kstrtoul(buf, 10, &state);
+	if (ret)
+		goto unlock;
+
+	if (state < 0 || state > 1) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	ret = led_set_flash_strobe(fled_cdev, state);
+	if (ret < 0)
+		goto unlock;
+	ret = size;
+unlock:
+	mutex_unlock(&led_cdev->led_access);
+	return ret;
+}
+
+static ssize_t flash_strobe_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	bool state;
+	int ret;
+
+	/* no lock needed for this */
+	ret = led_get_flash_strobe(fled_cdev, &state);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%u\n", state);
+}
+static DEVICE_ATTR_RW(flash_strobe);
+
+static ssize_t flash_timeout_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	unsigned long flash_timeout;
+	ssize_t ret;
+
+	mutex_lock(&led_cdev->led_access);
+
+	if (led_sysfs_is_disabled(led_cdev)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	ret = kstrtoul(buf, 10, &flash_timeout);
+	if (ret)
+		goto unlock;
+
+	ret = led_set_flash_timeout(fled_cdev, flash_timeout);
+	if (ret < 0)
+		goto unlock;
+
+	ret = size;
+unlock:
+	mutex_unlock(&led_cdev->led_access);
+	return ret;
+}
+
+static ssize_t flash_timeout_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+	return sprintf(buf, "%u\n", fled_cdev->timeout.val);
+}
+static DEVICE_ATTR_RW(flash_timeout);
+
+static ssize_t max_flash_timeout_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+	return sprintf(buf, "%u\n", fled_cdev->timeout.max);
+}
+static DEVICE_ATTR_RO(max_flash_timeout);
+
+static ssize_t flash_fault_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	u32 fault, mask = 0x1;
+	char *pbuf = buf;
+	int i, ret, buf_len;
+
+	ret = led_get_flash_fault(fled_cdev, &fault);
+	if (ret < 0)
+		return -EINVAL;
+
+	*buf = '\0';
+
+	for (i = 0; i < LED_NUM_FLASH_FAULTS; ++i) {
+		if (fault & mask) {
+			buf_len = sprintf(pbuf, "%s ",
+					  led_flash_fault_names[i]);
+			pbuf += buf_len;
+		}
+		mask <<= 1;
+	}
+
+	return sprintf(buf, "%s\n", buf);
+}
+static DEVICE_ATTR_RO(flash_fault);
+
+static ssize_t available_sync_leds_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	char *pbuf = buf;
+	int i, buf_len;
+
+	buf_len = sprintf(pbuf, "[0: none] ");
+	pbuf += buf_len;
+
+	for (i = 0; i < fled_cdev->num_sync_leds; ++i) {
+		buf_len = sprintf(pbuf, "[%d: %s] ", i + 1,
+				  fled_cdev->sync_leds[i]->led_cdev.name);
+		pbuf += buf_len;
+	}
+
+	return sprintf(buf, "%s\n", buf);
+}
+static DEVICE_ATTR_RO(available_sync_leds);
+
+static ssize_t flash_sync_strobe_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	unsigned long led_id;
+	ssize_t ret;
+
+	mutex_lock(&led_cdev->led_access);
+
+	if (led_sysfs_is_disabled(led_cdev)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	ret = kstrtoul(buf, 10, &led_id);
+	if (ret)
+		goto unlock;
+
+	if (led_id > fled_cdev->num_sync_leds) {
+		ret = -ERANGE;
+		goto unlock;
+	}
+
+	fled_cdev->sync_led_id = led_id;
+
+	ret = size;
+unlock:
+	mutex_unlock(&led_cdev->led_access);
+	return ret;
+}
+
+static ssize_t flash_sync_strobe_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	int sled_id = fled_cdev->sync_led_id;
+	char *sync_led_name = "none";
+
+	if (fled_cdev->sync_led_id > 0)
+		sync_led_name = (char *)
+			fled_cdev->sync_leds[sled_id - 1]->led_cdev.name;
+
+	return sprintf(buf, "[%d: %s]\n", sled_id, sync_led_name);
+}
+static DEVICE_ATTR_RW(flash_sync_strobe);
+
+static struct attribute *led_flash_strobe_attrs[] = {
+	&dev_attr_flash_strobe.attr,
+	NULL,
+};
+
+static struct attribute *led_flash_timeout_attrs[] = {
+	&dev_attr_flash_timeout.attr,
+	&dev_attr_max_flash_timeout.attr,
+	NULL,
+};
+
+static struct attribute *led_flash_brightness_attrs[] = {
+	&dev_attr_flash_brightness.attr,
+	&dev_attr_max_flash_brightness.attr,
+	NULL,
+};
+
+static struct attribute *led_flash_fault_attrs[] = {
+	&dev_attr_flash_fault.attr,
+	NULL,
+};
+
+static struct attribute *led_flash_sync_strobe_attrs[] = {
+	&dev_attr_available_sync_leds.attr,
+	&dev_attr_flash_sync_strobe.attr,
+	NULL,
+};
+
+static const struct attribute_group led_flash_strobe_group = {
+	.attrs = led_flash_strobe_attrs,
+};
+
+static const struct attribute_group led_flash_timeout_group = {
+	.attrs = led_flash_timeout_attrs,
+};
+
+static const struct attribute_group led_flash_brightness_group = {
+	.attrs = led_flash_brightness_attrs,
+};
+
+static const struct attribute_group led_flash_fault_group = {
+	.attrs = led_flash_fault_attrs,
+};
+
+static const struct attribute_group led_flash_sync_strobe_group = {
+	.attrs = led_flash_sync_strobe_attrs,
+};
+
+static void led_flash_resume(struct led_classdev *led_cdev)
+{
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+	call_flash_op(fled_cdev, flash_brightness_set,
+					fled_cdev->brightness.val);
+	call_flash_op(fled_cdev, timeout_set, fled_cdev->timeout.val);
+}
+
+static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev)
+{
+	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+	const struct led_flash_ops *ops = fled_cdev->ops;
+	const struct attribute_group **flash_groups = fled_cdev->sysfs_groups;
+
+	int num_sysfs_groups = 0;
+
+	flash_groups[num_sysfs_groups++] = &led_flash_strobe_group;
+
+	if (ops->flash_brightness_set)
+		flash_groups[num_sysfs_groups++] = &led_flash_brightness_group;
+
+	if (ops->timeout_set)
+		flash_groups[num_sysfs_groups++] = &led_flash_timeout_group;
+
+	if (ops->fault_get)
+		flash_groups[num_sysfs_groups++] = &led_flash_fault_group;
+
+	if (led_cdev->flags & LED_DEV_CAP_SYNC_STROBE)
+		flash_groups[num_sysfs_groups++] = &led_flash_sync_strobe_group;
+
+	led_cdev->groups = flash_groups;
+}
+
+int led_classdev_flash_register(struct device *parent,
+				struct led_classdev_flash *fled_cdev)
+{
+	struct led_classdev *led_cdev;
+	const struct led_flash_ops *ops;
+	int ret;
+
+	if (!fled_cdev)
+		return -EINVAL;
+
+	led_cdev = &fled_cdev->led_cdev;
+
+	if (led_cdev->flags & LED_DEV_CAP_FLASH) {
+		if (!led_cdev->brightness_set_sync)
+			return -EINVAL;
+
+		ops = fled_cdev->ops;
+		if (!ops || !ops->strobe_set)
+			return -EINVAL;
+
+		led_cdev->flash_resume = led_flash_resume;
+
+		/* Select the sysfs attributes to be created for the device */
+		led_flash_init_sysfs_groups(fled_cdev);
+	}
+
+	/* Register led class device */
+	ret = led_classdev_register(parent, led_cdev);
+	if (ret < 0)
+		return ret;
+
+	/* Setting a torch brightness needs to have immediate effect */
+	led_cdev->flags &= ~SET_BRIGHTNESS_ASYNC;
+	led_cdev->flags |= SET_BRIGHTNESS_SYNC;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(led_classdev_flash_register);
+
+void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev)
+{
+	if (!fled_cdev)
+		return;
+
+	led_classdev_unregister(&fled_cdev->led_cdev);
+}
+EXPORT_SYMBOL_GPL(led_classdev_flash_unregister);
+
+static void led_clamp_align(struct led_flash_setting *s)
+{
+	u32 v, offset;
+
+	v = s->val + s->step / 2;
+	v = clamp(v, s->min, s->max);
+	offset = v - s->min;
+	offset = s->step * (offset / s->step);
+	s->val = s->min + offset;
+}
+
+int led_set_flash_timeout(struct led_classdev_flash *fled_cdev, u32 timeout)
+{
+	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+	struct led_flash_setting *s = &fled_cdev->timeout;
+
+	s->val = timeout;
+	led_clamp_align(s);
+
+	if (!(led_cdev->flags & LED_SUSPENDED))
+		return call_flash_op(fled_cdev, timeout_set, s->val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(led_set_flash_timeout);
+
+int led_get_flash_fault(struct led_classdev_flash *fled_cdev, u32 *fault)
+{
+	return call_flash_op(fled_cdev, fault_get, fault);
+}
+EXPORT_SYMBOL_GPL(led_get_flash_fault);
+
+int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
+				u32 brightness)
+{
+	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+	struct led_flash_setting *s = &fled_cdev->brightness;
+
+	s->val = brightness;
+	led_clamp_align(s);
+
+	if (!(led_cdev->flags & LED_SUSPENDED))
+		return call_flash_op(fled_cdev, flash_brightness_set, s->val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(led_set_flash_brightness);
+
+int led_update_flash_brightness(struct led_classdev_flash *fled_cdev)
+{
+	struct led_flash_setting *s = &fled_cdev->brightness;
+	u32 brightness;
+
+	if (has_flash_op(fled_cdev, flash_brightness_get)) {
+		int ret = call_flash_op(fled_cdev, flash_brightness_get,
+						&brightness);
+		if (ret < 0)
+			return ret;
+
+		s->val = brightness;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(led_update_flash_brightness);
+
+MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
+MODULE_DESCRIPTION("LED Flash class interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 291ca45..795ec99 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -179,6 +179,10 @@ EXPORT_SYMBOL_GPL(led_classdev_suspend);
 void led_classdev_resume(struct led_classdev *led_cdev)
 {
 	led_cdev->brightness_set(led_cdev, led_cdev->brightness);
+
+	if (led_cdev->flash_resume)
+		led_cdev->flash_resume(led_cdev);
+
 	led_cdev->flags &= ~LED_SUSPENDED;
 }
 EXPORT_SYMBOL_GPL(led_classdev_resume);
diff --git a/include/linux/led-class-flash.h b/include/linux/led-class-flash.h
new file mode 100644
index 0000000..5ba2fac
--- /dev/null
+++ b/include/linux/led-class-flash.h
@@ -0,0 +1,207 @@
+/*
+ * LED Flash class interface
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __LINUX_FLASH_LEDS_H_INCLUDED
+#define __LINUX_FLASH_LEDS_H_INCLUDED
+
+#include <linux/leds.h>
+#include <uapi/linux/v4l2-controls.h>
+
+struct device_node;
+struct led_classdev_flash;
+
+/*
+ * Supported led fault bits - must be kept in synch
+ * with V4L2_FLASH_FAULT bits.
+ */
+#define LED_FAULT_OVER_VOLTAGE		(1 << 0)
+#define LED_FAULT_TIMEOUT		(1 << 1)
+#define LED_FAULT_OVER_TEMPERATURE	(1 << 2)
+#define LED_FAULT_SHORT_CIRCUIT		(1 << 3)
+#define LED_FAULT_OVER_CURRENT		(1 << 4)
+#define LED_FAULT_INDICATOR		(1 << 5)
+#define LED_FAULT_UNDER_VOLTAGE		(1 << 6)
+#define LED_FAULT_INPUT_VOLTAGE		(1 << 7)
+#define LED_FAULT_LED_OVER_TEMPERATURE	(1 << 8)
+#define LED_NUM_FLASH_FAULTS		9
+
+#define LED_FLASH_MAX_SYSFS_GROUPS 7
+
+struct led_flash_ops {
+	/* set flash brightness */
+	int (*flash_brightness_set)(struct led_classdev_flash *fled_cdev,
+					u32 brightness);
+	/* get flash brightness */
+	int (*flash_brightness_get)(struct led_classdev_flash *fled_cdev,
+					u32 *brightness);
+	/* set flash strobe state */
+	int (*strobe_set)(struct led_classdev_flash *fled_cdev, bool state);
+	/* get flash strobe state */
+	int (*strobe_get)(struct led_classdev_flash *fled_cdev, bool *state);
+	/* set flash timeout */
+	int (*timeout_set)(struct led_classdev_flash *fled_cdev, u32 timeout);
+	/* get the flash LED fault */
+	int (*fault_get)(struct led_classdev_flash *fled_cdev, u32 *fault);
+};
+
+/*
+ * Current value of a flash setting along
+ * with its constraints.
+ */
+struct led_flash_setting {
+	/* maximum allowed value */
+	u32 min;
+	/* maximum allowed value */
+	u32 max;
+	/* step value */
+	u32 step;
+	/* current value */
+	u32 val;
+};
+
+struct led_classdev_flash {
+	/* led class device */
+	struct led_classdev led_cdev;
+
+	/* flash led specific ops */
+	const struct led_flash_ops *ops;
+
+	/* flash brightness value in microamperes along with its constraints */
+	struct led_flash_setting brightness;
+
+	/* flash timeout value in microseconds along with its constraints */
+	struct led_flash_setting timeout;
+
+	/* LED Flash class sysfs groups */
+	const struct attribute_group *sysfs_groups[LED_FLASH_MAX_SYSFS_GROUPS];
+
+	/* LEDs available for flash strobe synchronization */
+	struct led_classdev_flash **sync_leds;
+
+	/* Number of LEDs available for flash strobe synchronization */
+	int num_sync_leds;
+
+	/*
+	 * The identifier of the sub-led to synchronize the flash strobe with.
+	 * Identifiers start from 1, which reflects the first element from the
+	 * sync_leds array. 0 means that the flash strobe should not be
+	 * synchronized.
+	 */
+	u32 sync_led_id;
+};
+
+static inline struct led_classdev_flash *lcdev_to_flcdev(
+						struct led_classdev *lcdev)
+{
+	return container_of(lcdev, struct led_classdev_flash, led_cdev);
+}
+
+/**
+ * led_classdev_flash_register - register a new object of led_classdev class
+ *				 with support for flash LEDs
+ * @parent: the flash LED to register
+ * @fled_cdev: the led_classdev_flash structure for this device
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+extern int led_classdev_flash_register(struct device *parent,
+				struct led_classdev_flash *fled_cdev);
+
+/**
+ * led_classdev_flash_unregister - unregisters an object of led_classdev class
+ *				   with support for flash LEDs
+ * @fled_cdev: the flash LED to unregister
+ *
+ * Unregister a previously registered via led_classdev_flash_register object
+ */
+extern void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev);
+
+/**
+ * led_set_flash_strobe - setup flash strobe
+ * @fled_cdev: the flash LED to set strobe on
+ * @state: 1 - strobe flash, 0 - stop flash strobe
+ *
+ * Strobe the flash LED.
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+static inline int led_set_flash_strobe(struct led_classdev_flash *fled_cdev,
+					bool state)
+{
+	return fled_cdev->ops->strobe_set(fled_cdev, state);
+}
+
+/**
+ * led_get_flash_strobe - get flash strobe status
+ * @fled_cdev: the flash LED to query
+ * @state: 1 - flash is strobing, 0 - flash is off
+ *
+ * Check whether the flash is strobing at the moment.
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+static inline int led_get_flash_strobe(struct led_classdev_flash *fled_cdev,
+					bool *state)
+{
+	if (fled_cdev->ops->strobe_get)
+		return fled_cdev->ops->strobe_get(fled_cdev, state);
+
+	return -EINVAL;
+}
+
+/**
+ * led_set_flash_brightness - set flash LED brightness
+ * @fled_cdev: the flash LED to set
+ * @brightness: the brightness to set it to
+ *
+ * Set a flash LED's brightness.
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+extern int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
+					u32 brightness);
+
+/**
+ * led_update_flash_brightness - update flash LED brightness
+ * @fled_cdev: the flash LED to query
+ *
+ * Get a flash LED's current brightness and update led_flash->brightness
+ * member with the obtained value.
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+extern int led_update_flash_brightness(struct led_classdev_flash *fled_cdev);
+
+/**
+ * led_set_flash_timeout - set flash LED timeout
+ * @fled_cdev: the flash LED to set
+ * @timeout: the flash timeout to set it to
+ *
+ * Set the flash strobe duration.
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+extern int led_set_flash_timeout(struct led_classdev_flash *fled_cdev,
+					u32 timeout);
+
+/**
+ * led_get_flash_fault - get the flash LED fault
+ * @fled_cdev: the flash LED to query
+ * @fault: bitmask containing flash faults
+ *
+ * Get the flash LED fault.
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+extern int led_get_flash_fault(struct led_classdev_flash *fled_cdev,
+					u32 *fault);
+
+#endif	/* __LINUX_FLASH_LEDS_H_INCLUDED */
diff --git a/include/linux/leds.h b/include/linux/leds.h
index cfceef3..f70f84f 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -46,6 +46,8 @@ struct led_classdev {
 #define LED_SYSFS_DISABLE	(1 << 20)
 #define SET_BRIGHTNESS_ASYNC	(1 << 21)
 #define SET_BRIGHTNESS_SYNC	(1 << 22)
+#define LED_DEV_CAP_FLASH	(1 << 23)
+#define LED_DEV_CAP_SYNC_STROBE	(1 << 24)
 
 	/* Set LED brightness level */
 	/* Must not sleep, use a workqueue if needed */
@@ -81,6 +83,7 @@ struct led_classdev {
 	unsigned long		 blink_delay_on, blink_delay_off;
 	struct timer_list	 blink_timer;
 	int			 blink_brightness;
+	void			(*flash_resume)(struct led_classdev *led_cdev);
 
 	struct work_struct	set_brightness_work;
 	int			delayed_set_value;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 02/19] Documentation: leds: Add description of LED Flash class extension
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
  2015-01-09 15:22 ` [PATCH/RFC v10 01/19] leds: Add LED Flash class extension to the LED subsystem Jacek Anaszewski
@ 2015-01-09 15:22 ` Jacek Anaszewski
  2015-01-09 17:40   ` Pavel Machek
  2015-01-09 15:22 ` [PATCH/RFC v10 03/19] DT: leds: Add led-sources property Jacek Anaszewski
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski

The documentation being added contains overall description of the
LED Flash Class and the related sysfs attributes.

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>
---
 Documentation/leds/leds-class-flash.txt |   57 +++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/leds/leds-class-flash.txt

diff --git a/Documentation/leds/leds-class-flash.txt b/Documentation/leds/leds-class-flash.txt
new file mode 100644
index 0000000..d80096b
--- /dev/null
+++ b/Documentation/leds/leds-class-flash.txt
@@ -0,0 +1,57 @@
+
+Flash LED handling under Linux
+==============================
+
+Some LED devices support two modes - torch and flash. In the LED subsystem
+those modes are supported by LED class (see Documentation/leds/leds-class.txt)
+and LED Flash class respectively. The torch mode related features are enabled
+by default and the flash ones only if a driver declares it by setting
+LED_DEV_CAP_FLASH flag.
+
+In order to enable support for flash LEDs CONFIG_LEDS_CLASS_FLASH symbol
+must be defined in the kernel config. A flash LED driver must register
+in the LED subsystem with led_classdev_flash_register function to gain flash
+related capabilities.
+
+There are flash LED devices which can control more than one LED and allow for
+strobing the sub-leds synchronously. A LED will be strobed synchronously with
+the one whose identifier is written to the flash_sync_strobe sysfs attribute.
+The list of available sub-led identifiers can be read from the available_sync_leds
+sysfs attribute. In order to enable the related settings the driver must set
+LED_DEV_CAP_SYNC_STROBE flag.
+
+Following sysfs attributes are exposed for controlling flash led devices:
+
+	- flash_brightness - flash LED brightness in microamperes (RW)
+	- max_flash_brightness - maximum available flash LED brightness (RO)
+	- flash_timeout - flash strobe duration in microseconds (RW)
+	- max_flash_timeout - maximum available flash strobe duration (RO)
+	- flash_strobe - flash strobe state (RW)
+	- available_sync_leds - list of sub-leds available for flash strobe
+				synchronization (RO)
+	- flash_sync_strobe - identifier of the sub-led to synchronize the flash
+			      strobe with; 0 stands for no synchronization (RW)
+	- flash_fault - bitmask of flash faults that may have occurred
+			possible flags are:
+		* 0x01 - flash controller voltage to the flash LED has exceeded
+			 the limit specific to the flash controller
+		* 0x02 - the flash strobe was still on when the timeout set by
+			 the user has expired; not all flash controllers may
+			 set this in all such conditions
+		* 0x04 - the flash controller has overheated
+		* 0x08 - the short circuit protection of the flash controller
+			 has been triggered
+		* 0x10 - current in the LED power supply has exceeded the limit
+			 specific to the flash controller
+		* 0x20 - the flash controller has detected a short or open
+			 circuit condition on the indicator LED
+		* 0x40 - flash controller voltage to the flash LED has been
+			 below the minimum limit specific to the flash
+		* 0x80 - the input voltage of the flash controller is below
+			 the limit under which strobing the flash at full
+			 current will not be possible. The condition persists
+			 until this flag is no longer set
+		* 0x100 - the temperature of the LED has exceeded its allowed
+			  upper limit
+
+		Flash faults are cleared, if possible, by reading the attribute.
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
  2015-01-09 15:22 ` [PATCH/RFC v10 01/19] leds: Add LED Flash class extension to the LED subsystem Jacek Anaszewski
  2015-01-09 15:22 ` [PATCH/RFC v10 02/19] Documentation: leds: Add description of LED Flash class extension Jacek Anaszewski
@ 2015-01-09 15:22 ` Jacek Anaszewski
  2015-01-09 17:42   ` Pavel Machek
       [not found]   ` <1420816989-1808-4-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2015-01-09 15:22 ` [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros Jacek Anaszewski
                   ` (15 subsequent siblings)
  18 siblings, 2 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

Add a property for defining the device outputs the LED
represented by the DT child node is connected to.

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: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
---
 Documentation/devicetree/bindings/leds/common.txt |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt
index a2c3f7a..29295bf 100644
--- a/Documentation/devicetree/bindings/leds/common.txt
+++ b/Documentation/devicetree/bindings/leds/common.txt
@@ -1,6 +1,10 @@
 Common leds properties.
 
 Optional properties for child nodes:
+- led-sources : Array of bits signifying the LED current regulator outputs the
+		LED represented by the child node is connected to (1 - the LED
+		is connected to the output, 0 - the LED isn't connected to the
+		output).
 - label : The label for this LED.  If omitted, the label is
   taken from the node name (excluding the unit address).
 
@@ -33,6 +37,7 @@ system-status {
 
 camera-flash {
 	label = "Flash";
+	led-sources = <1 0>;
 	max-microamp = <50000>;
 	flash-max-microamp = <320000>;
 	flash-timeout-us = <500000>;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (2 preceding siblings ...)
  2015-01-09 15:22 ` [PATCH/RFC v10 03/19] DT: leds: Add led-sources property Jacek Anaszewski
@ 2015-01-09 15:22 ` Jacek Anaszewski
  2015-01-09 17:43   ` Pavel Machek
  2015-01-20 11:12   ` Lee Jones
  2015-01-09 15:22 ` [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers Jacek Anaszewski
                   ` (14 subsequent siblings)
  18 siblings, 2 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski, Lee Jones,
	Chanwoo Choi

Add macros for max77693 led part related binding.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Chanwoo Choi <cw00.choi@samsung.com>
---
 include/dt-bindings/mfd/max77693.h |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 include/dt-bindings/mfd/max77693.h

diff --git a/include/dt-bindings/mfd/max77693.h b/include/dt-bindings/mfd/max77693.h
new file mode 100644
index 0000000..f53e197
--- /dev/null
+++ b/include/dt-bindings/mfd/max77693.h
@@ -0,0 +1,21 @@
+/*
+ * This header provides macros for MAX77693 device binding
+ *
+ * Copyright (C) 2014, Samsung Electronics Co., Ltd.
+ *
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ */
+
+#ifndef __DT_BINDINGS_MAX77693_H__
+#define __DT_BINDINGS_MAX77693_H
+
+/* External trigger type */
+#define MAX77693_LED_TRIG_TYPE_EDGE	0
+#define MAX77693_LED_TRIG_TYPE_LEVEL	1
+
+/* Boost modes */
+#define MAX77693_LED_BOOST_OFF		0
+#define MAX77693_LED_BOOST_ADAPTIVE	1
+#define MAX77693_LED_BOOST_FIXED	2
+
+#endif /* __DT_BINDINGS_MAX77693_H */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (3 preceding siblings ...)
  2015-01-09 15:22 ` [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros Jacek Anaszewski
@ 2015-01-09 15:22 ` Jacek Anaszewski
  2015-01-09 17:53   ` Pavel Machek
       [not found]   ` <1420816989-1808-6-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2015-01-09 15:22 ` [PATCH/RFC v10 06/19] mfd: max77693: modifications around max77693_led_platform_data Jacek Anaszewski
                   ` (13 subsequent siblings)
  18 siblings, 2 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski,
	Chanwoo Choi, Lee Jones

Change flash cell identifiers from max77693-flash to max77693-led
to avoid confusion with NOR/NAND Flash.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Chanwoo Choi <cw00.choi@samsung.com>
Cc: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/max77693.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
index a159593..cb14afa 100644
--- a/drivers/mfd/max77693.c
+++ b/drivers/mfd/max77693.c
@@ -53,8 +53,8 @@ static const struct mfd_cell max77693_devs[] = {
 		.of_compatible = "maxim,max77693-haptic",
 	},
 	{
-		.name = "max77693-flash",
-		.of_compatible = "maxim,max77693-flash",
+		.name = "max77693-led",
+		.of_compatible = "maxim,max77693-led",
 	},
 };
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 06/19] mfd: max77693: modifications around max77693_led_platform_data
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (4 preceding siblings ...)
  2015-01-09 15:22 ` [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers Jacek Anaszewski
@ 2015-01-09 15:22 ` Jacek Anaszewski
  2015-01-09 17:56   ` Pavel Machek
       [not found]   ` <1420816989-1808-7-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2015-01-09 15:22 ` [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros Jacek Anaszewski
                   ` (12 subsequent siblings)
  18 siblings, 2 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski,
	Chanwoo Choi, Lee Jones

1. Rename max77693_led_platform_data to max77693_led_config_data to
   avoid making impression that the led driver expects a board file -
   it relies on Device Tree data.
2. Remove fleds array, as the DT binding design has changed
3. Add "label" array for Device Tree strings with the name of a LED device
4. Make flash_timeout a two element array, for caching the sub-led
   related flash timeout.
5. Remove trigger array as the related data will not be provided
   in the DT binding

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Chanwoo Choi <cw00.choi@samsung.com>
Cc: Lee Jones <lee.jones@linaro.org>
---
 include/linux/mfd/max77693.h |    9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/include/linux/mfd/max77693.h b/include/linux/mfd/max77693.h
index f0b6585..c1ccb13 100644
--- a/include/linux/mfd/max77693.h
+++ b/include/linux/mfd/max77693.h
@@ -87,17 +87,16 @@ enum max77693_led_boost_mode {
 	MAX77693_LED_BOOST_FIXED,
 };
 
-struct max77693_led_platform_data {
-	u32 fleds[2];
+struct max77693_led_config_data {
+	const char *label[2];
 	u32 iout_torch[2];
 	u32 iout_flash[2];
-	u32 trigger[2];
-	u32 trigger_type[2];
+	u32 flash_timeout[2];
 	u32 num_leds;
 	u32 boost_mode;
-	u32 flash_timeout;
 	u32 boost_vout;
 	u32 low_vsys;
+	u32 trigger_type;
 };
 
 /* MAX77693 */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (5 preceding siblings ...)
  2015-01-09 15:22 ` [PATCH/RFC v10 06/19] mfd: max77693: modifications around max77693_led_platform_data Jacek Anaszewski
@ 2015-01-09 15:22 ` Jacek Anaszewski
  2015-01-09 17:59   ` Pavel Machek
  2015-01-20 11:17   ` Lee Jones
  2015-01-09 15:22 ` [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell Jacek Anaszewski
                   ` (11 subsequent siblings)
  18 siblings, 2 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski,
	Chanwoo Choi, Lee Jones

Modify FLASH_EN_SHIFT and TORCH_EN_SHIFT macros to work properly
when passed enum max77693_fled values (0 for FLED1 and 1 for FLED2)
from leds-max77693 driver.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Chanwoo Choi <cw00.choi@samsung.com>
Cc: Lee Jones <lee.jones@linaro.org>
---
 include/linux/mfd/max77693-private.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
index 08dae01..01799a9 100644
--- a/include/linux/mfd/max77693-private.h
+++ b/include/linux/mfd/max77693-private.h
@@ -113,8 +113,8 @@ enum max77693_pmic_reg {
 #define FLASH_EN_FLASH		0x1
 #define FLASH_EN_TORCH		0x2
 #define FLASH_EN_ON		0x3
-#define FLASH_EN_SHIFT(x)	(6 - ((x) - 1) * 2)
-#define TORCH_EN_SHIFT(x)	(2 - ((x) - 1) * 2)
+#define FLASH_EN_SHIFT(x)	(6 - (x) * 2)
+#define TORCH_EN_SHIFT(x)	(2 - (x) * 2)
 
 /* MAX77693 MAX_FLASH1 register */
 #define MAX_FLASH1_MAX_FL_EN	0x80
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (6 preceding siblings ...)
  2015-01-09 15:22 ` [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros Jacek Anaszewski
@ 2015-01-09 15:22 ` Jacek Anaszewski
       [not found]   ` <1420816989-1808-9-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2015-01-09 15:22 ` [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693 Jacek Anaszewski
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski,
	Andrzej Hajda, Lee Jones, Chanwoo Choi

This patch adds led-flash support to Maxim max77693 chipset.
A device can be exposed to user space through LED subsystem
sysfs interface. Device supports up to two leds which can
work in flash and torch mode. The leds can be triggered
externally or by software.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Bryan Wu <cooloney@gmail.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Chanwoo Choi <cw00.choi@samsung.com>
---
 drivers/leds/Kconfig         |   10 +
 drivers/leds/Makefile        |    1 +
 drivers/leds/leds-max77693.c | 1045 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1056 insertions(+)
 create mode 100644 drivers/leds/leds-max77693.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 95029df..ff9c21b 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -464,6 +464,16 @@ config LEDS_TCA6507
 	  LED driver chips accessed via the I2C bus.
 	  Driver support brightness control and hardware-assisted blinking.
 
+config LEDS_MAX77693
+	tristate "LED support for MAX77693 Flash"
+	depends on LEDS_CLASS_FLASH
+	depends on MFD_MAX77693
+	depends on OF
+	help
+	  This option enables support for the flash part of the MAX77693
+	  multifunction device. It has build in control for two leds in flash
+	  and torch mode.
+
 config LEDS_MAX8997
 	tristate "LED support for MAX8997 PMIC"
 	depends on LEDS_CLASS && MFD_MAX8997
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index cbba921..57ca62b 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
 obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
 obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
 obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
+obj-$(CONFIG_LEDS_MAX77693)		+= leds-max77693.o
 obj-$(CONFIG_LEDS_MAX8997)		+= leds-max8997.o
 obj-$(CONFIG_LEDS_LM355x)		+= leds-lm355x.o
 obj-$(CONFIG_LEDS_BLINKM)		+= leds-blinkm.o
diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
new file mode 100644
index 0000000..3ba07c4
--- /dev/null
+++ b/drivers/leds/leds-max77693.c
@@ -0,0 +1,1045 @@
+/*
+ * LED Flash class driver for the flash cell of max77693 mfd.
+ *
+ *	Copyright (C) 2015, Samsung Electronics Co., Ltd.
+ *
+ *	Authors: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *		 Andrzej Hajda <a.hajda@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <asm/div64.h>
+#include <linux/led-class-flash.h>
+#include <linux/mfd/max77693.h>
+#include <linux/mfd/max77693-private.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#define MODE_OFF		0
+#define MODE_FLASH(a)		(1 << (a))
+#define MODE_TORCH(a)		(1 << (2 + (a)))
+#define MODE_FLASH_EXTERNAL(a)	(1 << (4 + (a)))
+
+#define MODE_FLASH_MASK		(MODE_FLASH(FLED1) | MODE_FLASH(FLED2) | \
+				 MODE_FLASH_EXTERNAL(FLED1) | \
+				 MODE_FLASH_EXTERNAL(FLED2))
+#define MODE_TORCH_MASK		(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))
+
+#define FLED1_IOUT		(1 << 0)
+#define FLED2_IOUT		(1 << 1)
+
+enum max77693_fled {
+	FLED1,
+	FLED2,
+};
+
+enum max77693_led_mode {
+	FLASH,
+	TORCH,
+};
+
+struct max77693_sub_led {
+	/* related FLED output identifier */
+	int fled_id;
+	/* related LED Flash class device */
+	struct led_classdev_flash fled_cdev;
+	/* assures led-triggers compatibility */
+	struct work_struct work_brightness_set;
+
+	/* brightness cache */
+	unsigned int torch_brightness;
+	/* flash timeout cache */
+	unsigned int flash_timeout;
+};
+
+struct max77693_led_device {
+	/* parent mfd regmap */
+	struct regmap *regmap;
+	/* platform device data */
+	struct platform_device *pdev;
+	/* configuration data for the device */
+	struct max77693_led_config_data *cfg_data;
+	/* secures access to the device */
+	struct mutex lock;
+
+	/* sub led data */
+	struct max77693_sub_led sub_leds[2];
+
+	/* current flash timeout cache */
+	unsigned int current_flash_timeout;
+	/* ITORCH register cache */
+	u8 torch_iout_reg;
+	/* mode of fled outputs */
+	unsigned int mode_flags;
+	/* recently strobed fled */
+	int strobing_sub_led_id;
+	/* bitmask of fled outputs use state (bit 0. - FLED1, bit 1. - FLED2) */
+	u8 fled_mask;
+	/* fled modes that can be set */
+	u8 allowed_modes;
+
+	/* arrangement of current outputs */
+	bool iout_joint;
+};
+
+struct max77693_led_settings {
+	struct led_flash_setting torch_brightness;
+	struct led_flash_setting flash_brightness;
+	struct led_flash_setting flash_timeout;
+};
+
+static u8 max77693_led_iout_to_reg(u32 ua)
+{
+	if (ua < FLASH_IOUT_MIN)
+		ua = FLASH_IOUT_MIN;
+	return (ua - FLASH_IOUT_MIN) / FLASH_IOUT_STEP;
+}
+
+static u8 max77693_flash_timeout_to_reg(u32 us)
+{
+	return (us - FLASH_TIMEOUT_MIN) / FLASH_TIMEOUT_STEP;
+}
+
+static inline struct max77693_sub_led *flcdev_to_sub_led(
+					struct led_classdev_flash *fled_cdev)
+{
+	return container_of(fled_cdev, struct max77693_sub_led, fled_cdev);
+}
+
+static inline struct max77693_led_device *sub_led_to_led(
+					struct max77693_sub_led *sub_led)
+{
+	return container_of(sub_led, struct max77693_led_device,
+				sub_leds[sub_led->fled_id]);
+}
+
+static inline u8 max77693_led_vsys_to_reg(u32 mv)
+{
+	return ((mv - MAX_FLASH1_VSYS_MIN) / MAX_FLASH1_VSYS_STEP) << 2;
+}
+
+static inline u8 max77693_led_vout_to_reg(u32 mv)
+{
+	return (mv - FLASH_VOUT_MIN) / FLASH_VOUT_STEP + FLASH_VOUT_RMIN;
+}
+
+static inline bool max77693_fled_used(struct max77693_led_device *led,
+					 int fled_id)
+{
+	u8 fled_bit = (fled_id == FLED1) ? FLED1_IOUT : FLED2_IOUT;
+
+	return led->fled_mask & fled_bit;
+}
+
+/* split composite current @i into two @iout according to @imax weights */
+static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
+{
+	u64 t = i;
+
+	t *= imax[1];
+	do_div(t, imax[0] + imax[1]);
+
+	iout[1] = (u32)t / FLASH_IOUT_STEP * FLASH_IOUT_STEP;
+	iout[0] = i - iout[1];
+}
+
+static int max77693_set_mode(struct max77693_led_device *led, u8 mode)
+{
+	struct regmap *rmap = led->regmap;
+	int ret, v = 0, i;
+
+	for (i = FLED1; i <= FLED2; ++i) {
+		if (mode & MODE_TORCH(i))
+			v |= FLASH_EN_ON << TORCH_EN_SHIFT(i);
+
+		if (mode & MODE_FLASH(i)) {
+			v |= FLASH_EN_ON << FLASH_EN_SHIFT(i);
+		} else if (mode & MODE_FLASH_EXTERNAL(i)) {
+			v |= FLASH_EN_FLASH << FLASH_EN_SHIFT(i);
+			/*
+			 * Enable hw triggering also for torch mode, as some
+			 * camera sensors use torch led to fathom ambient light
+			 * conditions before strobing the flash.
+			 */
+			v |= FLASH_EN_TORCH << TORCH_EN_SHIFT(i);
+		}
+	}
+
+	/* Reset the register only prior setting flash modes */
+	if (mode & ~(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))) {
+		ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, 0);
+		if (ret < 0)
+			return ret;
+	}
+
+	return regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, v);
+}
+
+static void max77693_set_sync_strobe(struct max77693_led_device *led,
+					u8 *mode)
+{
+	struct max77693_sub_led *sub_leds = led->sub_leds;
+	struct led_classdev_flash *fled_cdev;
+	u8 m = *mode;
+
+	if (led->iout_joint)
+		return;
+
+	/* Check if the other sub-led wants to be strobed simultaneously. */
+	if (m & (MODE_FLASH(FLED1) | MODE_FLASH_EXTERNAL(FLED1))) {
+		fled_cdev = &sub_leds[FLED2].fled_cdev;
+		if (fled_cdev->sync_led_id)
+			m |= m << 1;
+	} else if (m & (MODE_FLASH(FLED2) | MODE_FLASH_EXTERNAL(FLED2))) {
+		fled_cdev = &sub_leds[FLED1].fled_cdev;
+		if (fled_cdev->sync_led_id)
+			m |= m >> 1;
+	}
+
+	*mode = m;
+}
+
+static int max77693_add_mode(struct max77693_led_device *led, u8 mode)
+{
+	int i, ret;
+
+	mode &= led->allowed_modes;
+
+	/*
+	 * Torch mode once enabled remains active until turned off. If the FLED2
+	 * output isn't to be disabled check if the torch mode to be set isn't
+	 * already activated and avoid re-setting it.
+	 */
+	if ((!(mode ^ led->mode_flags)) & MODE_TORCH(FLED2)) {
+		for (i = FLED1; i <= FLED2; ++i)
+			if ((mode & MODE_TORCH(i)) &&
+			    (led->mode_flags & MODE_TORCH(i)))
+				return 0;
+	}
+
+	/* Span the mode on FLED2 for joint iouts case */
+	if (led->iout_joint)
+		mode |= (mode << 1);
+
+	/* Span the flash mode on the other led if it is to be synchronized */
+	max77693_set_sync_strobe(led, &mode);
+
+	/*
+	 * FLASH_EXTERNAL mode activates FLASHEN and TORCHEN pins in the device.
+	 * The related register bits fields interfere with SW triggerred modes,
+	 * thus clear them to ensure proper device configuration.
+	 */
+	for (i = FLED1; i <= FLED2; ++i)
+		if (mode & MODE_FLASH_EXTERNAL(i))
+			led->mode_flags &= (~MODE_TORCH(i) & ~MODE_FLASH(i));
+
+	led->mode_flags |= mode;
+	led->mode_flags &= led->allowed_modes;
+
+	ret = max77693_set_mode(led, led->mode_flags);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Clear flash mode flag after setting the mode to avoid spurious flash
+	 * strobing on each subsequent torch mode setting.
+	 */
+	if (mode & MODE_FLASH_MASK)
+		led->mode_flags &= ~mode;
+
+	return ret;
+}
+
+static int max77693_clear_mode(struct max77693_led_device *led,
+				u8 mode)
+{
+	int ret;
+
+	if (led->iout_joint)
+		/* Clear mode also on FLED2 for joint iouts case */
+		mode |= (mode << 1);
+	else
+		/*
+		 * Clear a flash mode on the other led
+		 * if it is to be synchronized.
+		 */
+		max77693_set_sync_strobe(led, &mode);
+
+	led->mode_flags &= ~mode;
+
+	ret = max77693_set_mode(led, led->mode_flags);
+
+	return ret;
+}
+
+static void max77693_calc_iout(struct max77693_led_device *led, int fled_id,
+				u32 iout[2], u32 micro_amp, u32 iout_max[2],
+				enum max77693_led_mode mode)
+{
+	u8 blocked_modes;
+
+	if (fled_id == FLED1) {
+		if (led->iout_joint) {
+			/*
+			 * FLED2 must not be turned on to get
+			 * 15625 uA of total current.
+			 */
+			if (micro_amp == FLASH_IOUT_MIN) {
+				if (mode == FLASH)
+					blocked_modes =
+						MODE_FLASH(FLED2) |
+						MODE_FLASH_EXTERNAL(FLED2);
+				else
+					blocked_modes = MODE_TORCH(FLED2);
+
+				led->allowed_modes &= ~blocked_modes;
+			}
+		} else {
+			/*
+			 * Preclude splitting current to FLED2 if we
+			 * are driving two separate leds.
+			 */
+			iout_max[FLED2] = 0;
+		}
+		__max77693_calc_iout(iout, micro_amp, iout_max);
+	} else if (fled_id == FLED2) {
+		/*
+		 * Preclude splitting current to FLED1 if we
+		 * are driving two separate leds.
+		 */
+		iout_max[FLED1] = 0;
+		__max77693_calc_iout(iout, micro_amp, iout_max);
+	}
+}
+
+static int max77693_set_torch_current(struct max77693_led_device *led,
+				int fled_id, u32 micro_amp)
+{
+	struct max77693_led_config_data *cfg = led->cfg_data;
+	struct regmap *rmap = led->regmap;
+	u32 iout[2], iout_max[2];
+	u8 iout1_reg = 0, iout2_reg = 0;
+
+	iout_max[FLED1] = cfg->iout_torch[FLED1];
+	iout_max[FLED2] = cfg->iout_torch[FLED2];
+
+	led->allowed_modes |= MODE_TORCH_MASK;
+
+	max77693_calc_iout(led, fled_id, iout, micro_amp, iout_max,
+				TORCH);
+
+	if (fled_id == FLED1 || led->iout_joint) {
+		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);
+		led->torch_iout_reg &= 0xf0;
+	}
+	if (fled_id == FLED2 || led->iout_joint) {
+		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);
+		led->torch_iout_reg &= 0x0f;
+	}
+
+	led->torch_iout_reg |= ((iout1_reg << TORCH_IOUT1_SHIFT) |
+				(iout2_reg << TORCH_IOUT2_SHIFT));
+
+	return regmap_write(rmap, MAX77693_LED_REG_ITORCH,
+						led->torch_iout_reg);
+}
+
+static int max77693_set_flash_current(struct max77693_led_device *led,
+					int fled_id,
+					u32 micro_amp)
+{
+	struct max77693_led_config_data *cfg = led->cfg_data;
+	struct regmap *rmap = led->regmap;
+	u32 iout[2], iout_max[2];
+	u8 iout1_reg, iout2_reg;
+	int ret = -EINVAL;
+
+	iout_max[FLED1] = cfg->iout_flash[FLED1];
+	iout_max[FLED2] = cfg->iout_flash[FLED2];
+
+	led->allowed_modes |= MODE_FLASH_MASK;
+
+	max77693_calc_iout(led, fled_id, iout, micro_amp, iout_max,
+				FLASH);
+
+	if (fled_id == FLED1 || led->iout_joint) {
+		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);
+		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH1,
+							iout1_reg);
+		if (ret < 0)
+			return ret;
+	}
+	if (fled_id == FLED2 || led->iout_joint) {
+		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);
+		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH2,
+							iout2_reg);
+	}
+
+	return ret;
+}
+
+static int max77693_set_timeout(struct max77693_led_device *led, u32 microsec)
+{
+	struct max77693_led_config_data *cfg = led->cfg_data;
+	struct regmap *rmap = led->regmap;
+	u8 v;
+	int ret;
+
+	v = max77693_flash_timeout_to_reg(microsec);
+
+	if (cfg->trigger_type == MAX77693_LED_TRIG_TYPE_LEVEL)
+		v |= FLASH_TMR_LEVEL;
+
+	ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_TIMER, v);
+	if (ret < 0)
+		return ret;
+
+	led->current_flash_timeout = microsec;
+
+	return 0;
+}
+
+static int max77693_strobe_status_get(struct max77693_led_device *led,
+					bool *state)
+{
+	struct regmap *rmap = led->regmap;
+	unsigned int v;
+	int ret;
+
+	ret = regmap_read(rmap, MAX77693_LED_REG_FLASH_STATUS, &v);
+	if (ret < 0)
+		return ret;
+
+	*state = v & FLASH_STATUS_FLASH_ON;
+
+	return ret;
+}
+
+static int max77693_int_flag_get(struct max77693_led_device *led,
+					unsigned int *v)
+{
+	struct regmap *rmap = led->regmap;
+
+	return regmap_read(rmap, MAX77693_LED_REG_FLASH_INT, v);
+}
+
+static int max77693_setup(struct max77693_led_device *led)
+{
+	struct max77693_led_config_data *cfg = led->cfg_data;
+	struct regmap *rmap = led->regmap;
+	int i, first_led, last_led, ret;
+	u32 max_flash_curr[2];
+	u8 v;
+
+	/*
+	 * Initialize only flash current. Torch current doesn't
+	 * require initialization as ITORCH register is written with
+	 * new value each time brightness_set op is called.
+	 */
+	if (led->iout_joint) {
+		first_led = FLED1;
+		last_led = FLED1;
+		max_flash_curr[FLED1] = cfg->iout_flash[FLED1] +
+					cfg->iout_flash[FLED2];
+	} else {
+		first_led = max77693_fled_used(led, FLED1) ? FLED1 : FLED2;
+		last_led = led->cfg_data->num_leds == 2 ? FLED2 : first_led;
+		max_flash_curr[FLED1] = cfg->iout_flash[FLED1];
+		max_flash_curr[FLED2] = cfg->iout_flash[FLED2];
+	}
+
+	for (i = first_led; i <= last_led; ++i) {
+		ret = max77693_set_flash_current(led, i,
+					max_flash_curr[i]);
+		if (ret < 0)
+			return ret;
+	}
+
+	v = TORCH_TMR_NO_TIMER | MAX77693_LED_TRIG_TYPE_LEVEL;
+	ret = regmap_write(rmap, MAX77693_LED_REG_ITORCHTIMER, v);
+	if (ret < 0)
+		return ret;
+
+	/* initially set FLED1 timeout */
+	ret = max77693_set_timeout(led, cfg->flash_timeout[FLED1]);
+	if (ret < 0)
+		return ret;
+
+	if (cfg->low_vsys > 0)
+		v = max77693_led_vsys_to_reg(cfg->low_vsys) |
+						MAX_FLASH1_MAX_FL_EN;
+	else
+		v = 0;
+
+	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH1, v);
+	if (ret < 0)
+		return ret;
+	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH2, 0);
+	if (ret < 0)
+		return ret;
+
+	if (cfg->boost_mode == MAX77693_LED_BOOST_FIXED)
+		v = FLASH_BOOST_FIXED;
+	else
+		v = cfg->boost_mode | cfg->boost_mode << 1;
+
+	if (max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))
+		v |= FLASH_BOOST_LEDNUM_2;
+
+	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_CNTL, v);
+	if (ret < 0)
+		return ret;
+
+	v = max77693_led_vout_to_reg(cfg->boost_vout);
+	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_FLASH1, v);
+	if (ret < 0)
+		return ret;
+
+	/* Allow all modes on both fled outputs */
+	led->allowed_modes = MODE_FLASH_MASK | MODE_TORCH_MASK;
+
+	return max77693_set_mode(led, MODE_OFF);
+}
+
+static int __max77693_led_brightness_set(struct max77693_led_device *led,
+					int fled_id, enum led_brightness value)
+{
+	int ret;
+
+	mutex_lock(&led->lock);
+
+	if (value == 0) {
+		ret = max77693_clear_mode(led, MODE_TORCH(fled_id));
+		if (ret < 0)
+			dev_dbg(&led->pdev->dev,
+				"Failed to clear torch mode (%d)\n",
+				ret);
+		goto unlock;
+	}
+
+	ret = max77693_set_torch_current(led, fled_id, value * TORCH_IOUT_STEP);
+	if (ret < 0) {
+		dev_dbg(&led->pdev->dev,
+			"Failed to set torch current (%d)\n",
+			ret);
+		goto unlock;
+	}
+
+	ret = max77693_add_mode(led, MODE_TORCH(fled_id));
+	if (ret < 0)
+		dev_dbg(&led->pdev->dev,
+			"Failed to set torch mode (%d)\n",
+			ret);
+unlock:
+	mutex_unlock(&led->lock);
+	return ret;
+}
+
+static void max77693_led_brightness_set_work(
+					struct work_struct *work)
+{
+	struct max77693_sub_led *sub_led =
+			container_of(work, struct max77693_sub_led,
+					work_brightness_set);
+	struct max77693_led_device *led = sub_led_to_led(sub_led);
+
+	__max77693_led_brightness_set(led, sub_led->fled_id,
+				sub_led->torch_brightness);
+}
+
+/* LED subsystem callbacks */
+
+static int max77693_led_brightness_set_sync(
+				struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
+	struct max77693_led_device *led = sub_led_to_led(sub_led);
+
+	return __max77693_led_brightness_set(led, sub_led->fled_id, value);
+}
+
+static void max77693_led_brightness_set(
+				struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
+
+	sub_led->torch_brightness = value;
+	schedule_work(&sub_led->work_brightness_set);
+}
+
+static int max77693_led_flash_brightness_set(
+				struct led_classdev_flash *fled_cdev,
+				u32 brightness)
+{
+	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
+	struct max77693_led_device *led = sub_led_to_led(sub_led);
+	int ret;
+
+	mutex_lock(&led->lock);
+	ret = max77693_set_flash_current(led, sub_led->fled_id, brightness);
+	mutex_unlock(&led->lock);
+
+	return ret;
+}
+
+static int max77693_led_flash_strobe_set(
+				struct led_classdev_flash *fled_cdev,
+				bool state)
+{
+	struct max77693_sub_led *sub_led = flcdev_to_sub_led(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 (!state) {
+		ret = max77693_clear_mode(led, MODE_FLASH(fled_id));
+		goto unlock;
+	}
+
+	if (sub_led->flash_timeout != led->current_flash_timeout) {
+		ret = max77693_set_timeout(led, sub_led->flash_timeout);
+		if (ret < 0)
+			goto unlock;
+	}
+
+	led->strobing_sub_led_id = fled_id;
+
+	ret = max77693_add_mode(led, MODE_FLASH(fled_id));
+
+unlock:
+	mutex_unlock(&led->lock);
+	return ret;
+}
+
+static int max77693_led_flash_fault_get(
+				struct led_classdev_flash *fled_cdev,
+				u32 *fault)
+{
+	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
+	struct max77693_led_device *led = sub_led_to_led(sub_led);
+	unsigned int v;
+	int ret;
+
+	ret = max77693_int_flag_get(led, &v);
+	if (ret < 0)
+		return ret;
+
+	*fault = 0;
+
+	if (v & ((sub_led->fled_id == FLED1) ? FLASH_INT_FLED1_OPEN :
+					       FLASH_INT_FLED2_OPEN))
+		*fault |= LED_FAULT_OVER_VOLTAGE;
+	if (v & ((sub_led->fled_id == FLED1) ? FLASH_INT_FLED1_SHORT :
+					       FLASH_INT_FLED2_SHORT))
+		*fault |= LED_FAULT_SHORT_CIRCUIT;
+	if (v & FLASH_INT_OVER_CURRENT)
+		*fault |= LED_FAULT_OVER_CURRENT;
+
+	return 0;
+}
+
+static int max77693_led_flash_strobe_get(
+				struct led_classdev_flash *fled_cdev,
+				bool *state)
+{
+	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
+	struct max77693_led_device *led = sub_led_to_led(sub_led);
+	int ret;
+
+	if (!state)
+		return -EINVAL;
+
+	mutex_lock(&led->lock);
+
+	ret = max77693_strobe_status_get(led, state);
+
+	*state = !!(*state && (led->strobing_sub_led_id == sub_led->fled_id));
+
+
+	mutex_unlock(&led->lock);
+
+	return ret;
+}
+
+static int max77693_led_flash_timeout_set(
+				struct led_classdev_flash *fled_cdev,
+				u32 timeout)
+{
+	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
+	struct max77693_led_device *led = sub_led_to_led(sub_led);
+
+	mutex_lock(&led->lock);
+	sub_led->flash_timeout = timeout;
+	mutex_unlock(&led->lock);
+
+	return 0;
+}
+
+static int max77693_led_parse_dt(struct max77693_led_device *led,
+				 struct device_node *node)
+{
+	struct max77693_led_config_data *cfg = led->cfg_data;
+	struct max77693_sub_led *sub_leds = led->sub_leds;
+	struct device *dev = &led->pdev->dev;
+	struct device_node *child_node;
+	u32 led_sources[2];
+	int fled_id, ret;
+
+	of_property_read_u32(node, "maxim,trigger-type", &cfg->trigger_type);
+	of_property_read_u32(node, "maxim,boost-mode", &cfg->boost_mode);
+	of_property_read_u32(node, "maxim,boost-vout", &cfg->boost_vout);
+	of_property_read_u32(node, "maxim,vsys-min", &cfg->low_vsys);
+
+	for_each_available_child_of_node(node, child_node) {
+		ret = of_property_read_u32_array(child_node, "led-sources",
+							led_sources, 2);
+		if (ret < 0) {
+			dev_err(dev,
+				"Error reading \"led-sources\" DT property\n");
+			return ret;
+		}
+
+		if (led_sources[0] && led_sources[1]) {
+			fled_id = FLED1;
+			led->fled_mask = FLED1_IOUT | FLED2_IOUT;
+		} else if (led_sources[0] && !led_sources[1]) {
+			fled_id = FLED1;
+			led->fled_mask |= FLED1_IOUT;
+		} else if (!led_sources[0] && led_sources[1]) {
+			fled_id = FLED2;
+			led->fled_mask |= FLED2_IOUT;
+		} else {
+			dev_err(dev,
+				"Wrong \"led-sources\" DT property value\n");
+			return -EINVAL;
+		}
+
+		sub_leds[fled_id].fled_id = fled_id;
+
+		ret = of_property_read_string(child_node, "label",
+					(const char **) &cfg->label[fled_id]);
+		if (ret < 0) {
+			dev_err(dev, "Error reading \"label\" DT property\n");
+			return ret;
+		}
+
+		of_property_read_u32(child_node, "max-microamp",
+						&cfg->iout_torch[fled_id]);
+		of_property_read_u32(child_node, "flash-max-microamp",
+						&cfg->iout_flash[fled_id]);
+		of_property_read_u32(child_node, "flash-timeout-us",
+						&cfg->flash_timeout[fled_id]);
+
+		if (++led->cfg_data->num_leds == 2 ||
+		    (max77693_fled_used(led, FLED1) &&
+		     max77693_fled_used(led, FLED2)))
+			break;
+	}
+
+	return 0;
+}
+
+static void clamp_align(u32 *v, u32 min, u32 max, u32 step)
+{
+	*v = clamp_val(*v, min, max);
+	if (step > 1)
+		*v = (*v - min) / step * step + min;
+}
+
+static void max77693_led_validate_configuration(struct max77693_led_device *led)
+{
+	struct max77693_led_config_data *cfg = led->cfg_data;
+	int i;
+
+	if (led->cfg_data->num_leds == 1 &&
+	    max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))
+		led->iout_joint = true;
+
+	cfg->boost_mode = clamp_val(cfg->boost_mode, MAX77693_LED_BOOST_NONE,
+			    MAX77693_LED_BOOST_FIXED);
+
+	/* Boost must be enabled if both current outputs are used */
+	if ((cfg->boost_mode == MAX77693_LED_BOOST_NONE) && led->iout_joint)
+		cfg->boost_mode = MAX77693_LED_BOOST_FIXED;
+
+	/* Split max current settings to both outputs in case of joint leds */
+	if (led->iout_joint) {
+		cfg->iout_torch[FLED1] /= 2;
+		cfg->iout_torch[FLED2] = cfg->iout_torch[FLED1];
+		cfg->iout_flash[FLED1] /= 2;
+		cfg->iout_flash[FLED2] = cfg->iout_flash[FLED1];
+	}
+
+	for (i = FLED1; i <= FLED2; ++i) {
+		if (max77693_fled_used(led, i)) {
+			clamp_align(&cfg->iout_torch[i], TORCH_IOUT_MIN,
+					TORCH_IOUT_MAX, TORCH_IOUT_STEP);
+			clamp_align(&cfg->iout_flash[i], FLASH_IOUT_MIN,
+					cfg->boost_mode ? FLASH_IOUT_MAX_2LEDS :
+							FLASH_IOUT_MAX_1LED,
+					FLASH_IOUT_STEP);
+		} else {
+			cfg->iout_torch[i] = cfg->iout_flash[i] = 0;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cfg->flash_timeout); ++i)
+		clamp_align(&cfg->flash_timeout[i], FLASH_TIMEOUT_MIN,
+				FLASH_TIMEOUT_MAX, FLASH_TIMEOUT_STEP);
+
+	cfg->trigger_type = clamp_val(cfg->trigger_type,
+					MAX77693_LED_TRIG_TYPE_EDGE,
+					MAX77693_LED_TRIG_TYPE_LEVEL);
+
+	clamp_align(&cfg->boost_vout, FLASH_VOUT_MIN, FLASH_VOUT_MAX,
+							FLASH_VOUT_STEP);
+
+	if (cfg->low_vsys)
+		clamp_align(&cfg->low_vsys, MAX_FLASH1_VSYS_MIN,
+				MAX_FLASH1_VSYS_MAX, MAX_FLASH1_VSYS_STEP);
+}
+
+static int max77693_led_get_configuration(struct max77693_led_device *led)
+{
+	struct device *dev = &led->pdev->dev;
+	int ret;
+
+	if (!dev->of_node)
+		return -EINVAL;
+
+	led->cfg_data = devm_kzalloc(dev, sizeof(*led->cfg_data), GFP_KERNEL);
+	if (!led->cfg_data)
+		return -ENOMEM;
+
+	ret = max77693_led_parse_dt(led, dev->of_node);
+	if (ret < 0)
+		return ret;
+
+	max77693_led_validate_configuration(led);
+
+	return 0;
+}
+
+static const struct led_flash_ops flash_ops = {
+	.flash_brightness_set	= max77693_led_flash_brightness_set,
+	.strobe_set		= max77693_led_flash_strobe_set,
+	.strobe_get		= max77693_led_flash_strobe_get,
+	.timeout_set		= max77693_led_flash_timeout_set,
+	.fault_get		= max77693_led_flash_fault_get,
+};
+
+static void max77693_init_flash_settings(struct max77693_led_device *led,
+					 struct max77693_led_settings *s,
+					 int fled_id)
+{
+	struct max77693_led_config_data *cfg = led->cfg_data;
+	struct led_flash_setting *setting;
+
+	/* Init torch intensity setting */
+	setting = &s->torch_brightness;
+	setting->min = TORCH_IOUT_MIN;
+	setting->max = cfg->iout_torch[fled_id];
+	setting->max = led->iout_joint ?
+			cfg->iout_torch[FLED1] + cfg->iout_torch[FLED2] :
+			cfg->iout_torch[fled_id];
+	setting->step = TORCH_IOUT_STEP;
+	setting->val = setting->max;
+
+	/* Init flash intensity setting */
+	setting = &s->flash_brightness;
+	setting->min = FLASH_IOUT_MIN;
+	setting->max = led->iout_joint ?
+			cfg->iout_flash[FLED1] + cfg->iout_flash[FLED2] :
+			cfg->iout_flash[fled_id];
+	setting->step = FLASH_IOUT_STEP;
+	setting->val = setting->max;
+
+	/* Init flash timeout setting */
+	setting = &s->flash_timeout;
+	setting->min = FLASH_TIMEOUT_MIN;
+	setting->max = cfg->flash_timeout[fled_id];
+	setting->step = FLASH_TIMEOUT_STEP;
+	setting->val = setting->max;
+}
+
+static int max77693_set_available_sync_led(struct max77693_led_device *led,
+						int fled_id)
+{
+	struct max77693_sub_led *sub_led = &led->sub_leds[fled_id];
+	struct led_classdev_flash *fled_cdev = &sub_led->fled_cdev;
+
+	fled_cdev->sync_leds = devm_kzalloc(&led->pdev->dev, sizeof(fled_cdev),
+					GFP_KERNEL);
+	if (!fled_cdev->sync_leds)
+		return -ENOMEM;
+
+	fled_cdev->sync_leds[0] = &led->sub_leds[!fled_id].fled_cdev;
+	fled_cdev->num_sync_leds = 1;
+
+	return 0;
+}
+
+static void max77693_init_fled_cdev(struct max77693_led_device *led,
+					int fled_id)
+{
+	struct led_classdev_flash *fled_cdev;
+	struct led_classdev *led_cdev;
+	struct max77693_sub_led *sub_led = &led->sub_leds[fled_id];
+	struct max77693_led_settings settings;
+
+	/* Initialize flash settings */
+	max77693_init_flash_settings(led, &settings, fled_id);
+
+	/* Initialize LED Flash class device */
+	fled_cdev = &sub_led->fled_cdev;
+	fled_cdev->ops = &flash_ops;
+	led_cdev = &fled_cdev->led_cdev;
+	led_cdev->name = led->cfg_data->label[fled_id];
+	led_cdev->brightness_set = max77693_led_brightness_set;
+	led_cdev->brightness_set_sync = max77693_led_brightness_set_sync;
+	INIT_WORK(&sub_led->work_brightness_set,
+			max77693_led_brightness_set_work);
+
+	led_cdev->max_brightness = settings.torch_brightness.val /
+					TORCH_IOUT_STEP;
+	led_cdev->flags |= LED_DEV_CAP_FLASH;
+	if (led->cfg_data->num_leds == 2)
+		led_cdev->flags |= LED_DEV_CAP_SYNC_STROBE;
+
+	fled_cdev->brightness = settings.flash_brightness;
+	fled_cdev->timeout = settings.flash_timeout;
+	sub_led->flash_timeout = fled_cdev->timeout.val;
+}
+
+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;
+	int init_fled_cdev[2], i, ret;
+
+	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
+	if (!led)
+		return -ENOMEM;
+
+	led->pdev = pdev;
+	led->regmap = iodev->regmap;
+	sub_leds = led->sub_leds;
+
+	platform_set_drvdata(pdev, led);
+	ret = max77693_led_get_configuration(led);
+	if (ret < 0)
+		return ret;
+
+	ret = max77693_setup(led);
+	if (ret < 0)
+		return ret;
+
+	init_fled_cdev[FLED1] =
+			led->iout_joint || max77693_fled_used(led, FLED1);
+	init_fled_cdev[FLED2] =
+			!led->iout_joint && max77693_fled_used(led, FLED2);
+
+	/* Initialize LED Flash class device(s) */
+	for (i = FLED1; i <= FLED2; ++i)
+		if (init_fled_cdev[i])
+			max77693_init_fled_cdev(led, i);
+
+	/* Setup sub-leds available for flash strobe synchronization */
+	if (led->cfg_data->num_leds == 2) {
+		for (i = FLED1; i <= FLED2; ++i) {
+			ret = max77693_set_available_sync_led(led, i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	mutex_init(&led->lock);
+
+	/* Register LED Flash class device(s) */
+	for (i = FLED1; i <= FLED2; ++i) {
+		if (init_fled_cdev[i]) {
+			ret = led_classdev_flash_register(dev,
+							&sub_leds[i].fled_cdev);
+			if (ret < 0) {
+				/*
+				 * At this moment FLED1 might have been already
+				 * registered and it needs to be released.
+				 */
+				if (i == FLED2)
+					goto err_register_led2;
+				else
+					goto err_register_led1;
+			}
+		}
+	}
+
+
+	return 0;
+
+err_register_led2:
+	/* It is possible than only FLED2 was to be registered */
+	if (!init_fled_cdev[FLED1])
+		goto err_register_led1;
+	led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
+err_register_led1:
+	mutex_destroy(&led->lock);
+
+	return ret;
+}
+
+static int max77693_led_remove(struct platform_device *pdev)
+{
+	struct max77693_led_device *led = platform_get_drvdata(pdev);
+	struct max77693_sub_led *sub_leds = led->sub_leds;
+
+	if (led->iout_joint || max77693_fled_used(led, FLED1)) {
+		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)) {
+		led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);
+		cancel_work_sync(&sub_leds[FLED2].work_brightness_set);
+	}
+
+	mutex_destroy(&led->lock);
+
+	return 0;
+}
+
+static struct of_device_id max77693_led_dt_match[] = {
+	{.compatible = "maxim,max77693-led"},
+	{},
+};
+
+static struct platform_driver max77693_led_driver = {
+	.probe		= max77693_led_probe,
+	.remove		= max77693_led_remove,
+	.driver		= {
+		.name	= "max77693-led",
+		.owner	= THIS_MODULE,
+		.of_match_table = max77693_led_dt_match,
+	},
+};
+
+module_platform_driver(max77693_led_driver);
+
+MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
+MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
+MODULE_DESCRIPTION("Maxim MAX77693 led flash driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (7 preceding siblings ...)
  2015-01-09 15:22 ` [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell Jacek Anaszewski
@ 2015-01-09 15:22 ` Jacek Anaszewski
  2015-01-09 17:52   ` Pavel Machek
  2015-01-20 11:21   ` Lee Jones
       [not found] ` <1420816989-1808-1-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
                   ` (9 subsequent siblings)
  18 siblings, 2 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:22 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski,
	Andrzej Hajda, Lee Jones, Chanwoo Choi, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala

This patch adds device tree binding documentation for
the flash cell of the Maxim max77693 multifunctional device.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Chanwoo Choi <cw00.choi@samsung.com>
Cc: Bryan Wu <cooloney@gmail.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
---
 Documentation/devicetree/bindings/mfd/max77693.txt |   69 ++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
index 01e9f30..ef184f0 100644
--- a/Documentation/devicetree/bindings/mfd/max77693.txt
+++ b/Documentation/devicetree/bindings/mfd/max77693.txt
@@ -41,7 +41,52 @@ Optional properties:
 	 To get more informations, please refer to documentaion.
 	[*] refer Documentation/devicetree/bindings/pwm/pwm.txt
 
+- led : the LED submodule device node
+
+There are two led outputs available - fled1 and fled2. Each of them can
+control a separate led or they can be connected together to double
+the maximum current for a single connected led. One led is represented
+by one child node.
+
+Required properties:
+- compatible : Must be "maxim,max77693-led".
+
+Optional properties:
+- maxim,trigger-type : Flash trigger type.
+	Possible trigger types:
+		MAX77693_LED_TRIG_TYPE_EDGE - Rising edge of the signal triggers
+			the flash,
+		MAX77693_LED_TRIG_TYPE_LEVEL - Strobe pulse length controls
+			duration of the flash.
+- maxim,boost-mode :
+	In boost mode the device can produce up to 1.2A of total current
+	on both outputs. The maximum current on each output is reduced
+	to 625mA then. If not enabled explicitly, boost setting defaults to
+	MAX77693_LED_BOOST_FIXED in case both current sources are used.
+	Possible values:
+		MAX77693_LED_BOOST_OFF - no boost,
+		MAX77693_LED_BOOST_ADAPTIVE - adaptive mode,
+		MAX77693_LED_BOOST_FIXED - fixed mode.
+- maxim,boost-vout : Output voltage of the boost module in millivolts.
+- maxim,vsys-min : Low input voltage level in millivolts. Flash is not fired
+	if chip estimates that system voltage could drop below this level due
+	to flash power consumption.
+
+Required properties of the LED child node:
+- label : see Documentation/devicetree/bindings/leds/common.txt
+- led-sources : see Documentation/devicetree/bindings/leds/common.txt
+
+Optional properties of the LED child node:
+- max-microamp : see Documentation/devicetree/bindings/leds/common.txt
+		Range: 15625 - 250000
+- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
+		Range: 15625 - 1000000
+- flash-timeout-us : see Documentation/devicetree/bindings/leds/common.txt
+		Range: 62500 - 1000000
+
 Example:
+#include <dt-bindings/mfd/max77693.h>
+
 	max77693@66 {
 		compatible = "maxim,max77693";
 		reg = <0x66>;
@@ -73,4 +118,28 @@ Example:
 			pwms = <&pwm 0 40000 0>;
 			pwm-names = "haptic";
 		};
+
+		led {
+			compatible = "maxim,max77693-led";
+			maxim,trigger-type = <MAX77693_LED_TRIG_TYPE_LEVEL>;
+			maxim,boost-mode = <MAX77693_LED_BOOST_FIXED>;
+			maxim,boost-vout = <5000>;
+			maxim,vsys-min = <2400>;
+
+			camera1_flash: led1 {
+				label = "max77693-flash1";
+				led-sources = <1 0>;
+				max-microamp = <250000>;
+				flash-max-microamp = <625000>;
+				flash-timeout-us = <1000000>;
+			};
+
+			camera2_flash: led2 {
+				label = "max77693-flash2";
+				led-sources = <0 1>;
+				max-microamp = <250000>;
+				flash-max-microamp = <625000>;
+				flash-timeout-us = <1000000>;
+			};
+		};
 	};
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 10/19] leds: Add driver for AAT1290 current regulator
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
@ 2015-01-09 15:23     ` Jacek Anaszewski
  2015-01-09 15:22 ` [PATCH/RFC v10 02/19] Documentation: leds: Add description of LED Flash class extension Jacek Anaszewski
                       ` (17 subsequent siblings)
  18 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ, pavel-+ZI9xUNit7I,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Jacek Anaszewski

This patch adds a driver for the 1.5A Step-Up Current Regulator
for Flash LEDs. The device is programmed through a Skyworks proprietary
AS2Cwire serial digital interface.

Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Cc: Bryan Wu <cooloney-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Richard Purdie <rpurdie-Fm38FmjxZ/leoWH0uzbU5w@public.gmane.org>
---
 drivers/leds/Kconfig        |    7 +
 drivers/leds/Makefile       |    1 +
 drivers/leds/leds-aat1290.c |  398 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 406 insertions(+)
 create mode 100644 drivers/leds/leds-aat1290.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index ff9c21b..d70fc7b 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -39,6 +39,13 @@ config LEDS_88PM860X
 	  This option enables support for on-chip LED drivers found on Marvell
 	  Semiconductor 88PM8606 PMIC.
 
+config LEDS_AAT1290
+	tristate "LED support for the AAT1290"
+	depends on LEDS_CLASS_FLASH
+	depends on OF
+	help
+	 This option enables support for the LEDs on the AAT1290.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 57ca62b..b802251 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_LEDS_TRIGGERS)		+= led-triggers.o
 
 # LED Platform Drivers
 obj-$(CONFIG_LEDS_88PM860X)		+= leds-88pm860x.o
+obj-$(CONFIG_LEDS_AAT1290)		+= leds-aat1290.o
 obj-$(CONFIG_LEDS_BD2802)		+= leds-bd2802.o
 obj-$(CONFIG_LEDS_LOCOMO)		+= leds-locomo.o
 obj-$(CONFIG_LEDS_LM3530)		+= leds-lm3530.o
diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c
new file mode 100644
index 0000000..0a3c9b4
--- /dev/null
+++ b/drivers/leds/leds-aat1290.c
@@ -0,0 +1,398 @@
+/*
+ *	LED Flash class driver for the AAT1290
+ *	1.5A Step-Up Current Regulator for Flash LEDs
+ *
+ *	Copyright (C) 2015, Samsung Electronics Co., Ltd.
+ *	Author: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/led-class-flash.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#define AAT1290_MOVIE_MODE_CURRENT_ADDR	17
+#define AAT1290_MAX_MM_CURR_PERCENT_0	16
+#define AAT1290_MAX_MM_CURR_PERCENT_100	1
+
+#define AAT1290_FLASH_SAFETY_TIMER_ADDR	18
+
+#define AAT1290_MOVIE_MODE_CONFIG_ADDR	19
+#define AAT1290_MOVIE_MODE_OFF		1
+#define AAT1290_MOVIE_MODE_ON		3
+
+#define AAT1290_MM_CURRENT_RATIO_ADDR	20
+#define AAT1290_MM_TO_FL_1_92		1
+#define AAT1290_MM_TO_FL_3_7		2
+#define AAT1290_MM_TO_FL_5_5		3
+#define AAT1290_MM_TO_FL_7_3		4
+#define AAT1290_MM_TO_FL_9		5
+#define AAT1290_MM_TO_FL_10_7		6
+#define AAT1290_MM_TO_FL_12_4		7
+#define AAT1290_MM_TO_FL_14		8
+#define AAT1290_MM_TO_FL_15_9		9
+#define AAT1290_MM_TO_FL_17_5		10
+#define AAT1290_MM_TO_FL_19_1		11
+#define AAT1290_MM_TO_FL_20_8		12
+#define AAT1290_MM_TO_FL_22_4		13
+#define AAT1290_MM_TO_FL_24		14
+#define AAT1290_MM_TO_FL_25_6		15
+#define AAT1290_MM_TO_FL_OFF		16
+
+#define AAT1290_LATCH_TIME_MIN_US	500
+#define AAT1290_LATCH_TIME_MAX_US	1000
+#define AAT1290_EN_SET_TICK_TIME_US	1
+#define AAT1290_FLEN_OFF_DELAY_TIME_US	10
+#define AAT1290_FLASH_TM_NUM_LEVELS	16
+
+struct aat1290_led_settings {
+	struct led_flash_setting torch_brightness;
+	struct led_flash_setting flash_brightness;
+	struct led_flash_setting flash_timeout;
+};
+
+struct aat1290_led {
+	struct platform_device *pdev;
+	struct mutex lock;
+
+	struct led_classdev_flash fled_cdev;
+
+	int flen_gpio;
+	int en_set_gpio;
+
+	u32 max_flash_tm;
+	bool movie_mode;
+
+	char *label;
+	unsigned int torch_brightness;
+	unsigned int flash_timeout;
+	struct work_struct work_brightness_set;
+};
+
+static struct aat1290_led *fled_cdev_to_led(
+				struct led_classdev_flash *fled_cdev)
+{
+	return container_of(fled_cdev, struct aat1290_led, fled_cdev);
+}
+
+static void aat1290_as2cwire_write(struct aat1290_led *led, int addr, int value)
+{
+	int i;
+
+	gpio_set_value(led->flen_gpio, 0);
+	gpio_set_value(led->en_set_gpio, 0);
+
+	udelay(AAT1290_FLEN_OFF_DELAY_TIME_US);
+
+	/* write address */
+	for (i = 0; i < addr; ++i) {
+		udelay(AAT1290_EN_SET_TICK_TIME_US);
+		gpio_set_value(led->en_set_gpio, 0);
+		udelay(AAT1290_EN_SET_TICK_TIME_US);
+		gpio_set_value(led->en_set_gpio, 1);
+	}
+
+	usleep_range(AAT1290_LATCH_TIME_MIN_US, AAT1290_LATCH_TIME_MAX_US);
+
+	/* write data */
+	for (i = 0; i < value; ++i) {
+		udelay(AAT1290_EN_SET_TICK_TIME_US);
+		gpio_set_value(led->en_set_gpio, 0);
+		udelay(AAT1290_EN_SET_TICK_TIME_US);
+		gpio_set_value(led->en_set_gpio, 1);
+	}
+
+	usleep_range(AAT1290_LATCH_TIME_MIN_US, AAT1290_LATCH_TIME_MAX_US);
+}
+
+static void aat1290_set_flash_safety_timer(struct aat1290_led *led,
+					unsigned int micro_sec)
+{
+	struct led_classdev_flash *fled_cdev = &led->fled_cdev;
+	struct led_flash_setting *flash_tm = &fled_cdev->timeout;
+	int flash_tm_reg = AAT1290_FLASH_TM_NUM_LEVELS -
+				(micro_sec / flash_tm->step) + 1;
+
+	aat1290_as2cwire_write(led, AAT1290_FLASH_SAFETY_TIMER_ADDR,
+							flash_tm_reg);
+}
+
+static void aat1290_brightness_set(struct aat1290_led *led,
+					enum led_brightness brightness)
+{
+	mutex_lock(&led->lock);
+
+	if (brightness == 0) {
+		gpio_set_value(led->flen_gpio, 0);
+		gpio_set_value(led->en_set_gpio, 0);
+		goto unlock;
+	}
+
+	if (!led->movie_mode) {
+		aat1290_as2cwire_write(led, AAT1290_MM_CURRENT_RATIO_ADDR,
+					AAT1290_MM_TO_FL_1_92);
+		led->movie_mode = true;
+	}
+
+	aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CURRENT_ADDR,
+				AAT1290_MAX_MM_CURR_PERCENT_0 - brightness);
+	aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CONFIG_ADDR,
+				AAT1290_MOVIE_MODE_ON);
+unlock:
+	mutex_unlock(&led->lock);
+}
+
+/* LED subsystem callbacks */
+
+static void aat1290_brightness_set_work(struct work_struct *work)
+{
+	struct aat1290_led *led =
+		container_of(work, struct aat1290_led, work_brightness_set);
+
+	aat1290_brightness_set(led, led->torch_brightness);
+}
+
+static void aat1290_led_brightness_set(struct led_classdev *led_cdev,
+					enum led_brightness brightness)
+{
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
+
+	led->torch_brightness = brightness;
+	schedule_work(&led->work_brightness_set);
+}
+
+static int aat1290_led_brightness_set_sync(struct led_classdev *led_cdev,
+					enum led_brightness brightness)
+{
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
+
+	aat1290_brightness_set(led, brightness);
+
+	return 0;
+}
+
+static int aat1290_led_flash_strobe_set(struct led_classdev_flash *fled_cdev,
+					 bool state)
+
+{
+	struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
+	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+	struct led_flash_setting *timeout = &fled_cdev->timeout;
+
+	mutex_lock(&led->lock);
+
+	if (state == 0) {
+		gpio_set_value(led->flen_gpio, 0);
+		gpio_set_value(led->en_set_gpio, 0);
+		goto unlock;
+	}
+
+	aat1290_set_flash_safety_timer(led, timeout->val);
+
+	/*
+	 * To reenter movie mode after a flash event the part
+	 * must be cycled off and back on to reset the movie
+	 * mode and reprogrammed via the AS2Cwire. Therefore
+	 * the brightness value needs to be updated here to
+	 * reflect the actual state.
+	 */
+	led_cdev->brightness = 0;
+	led->movie_mode = false;
+
+	gpio_set_value(led->flen_gpio, 1);
+
+unlock:
+	mutex_unlock(&led->lock);
+
+	return 0;
+}
+
+static int aat1290_led_flash_timeout_set(struct led_classdev_flash *fled_cdev,
+						u32 timeout)
+{
+	/*
+	 * Don't do anything - flash timeout is cached in the led-class-flash
+	 * core and will be applied in the strobe_set op, as writing the
+	 * safety timer register spuriously turns the torch mode on.
+	 */
+
+	return 0;
+}
+
+static int aat1290_led_parse_dt(struct aat1290_led *led,
+				struct device *dev)
+{
+	int ret;
+
+	ret = of_property_read_string(dev->of_node, "label",
+				(const char **) &led->label);
+	if (ret < 0) {
+		dev_err(dev, "Error reading \"label\" DT property (%d)\n", ret);
+		return ret;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "flash-timeout-us",
+				&led->max_flash_tm);
+	if (ret < 0)
+		dev_err(dev, "Error reading \"flash-timeout-us\" DT property (%d)\n",
+			ret);
+
+	return ret;
+}
+
+static void aat1290_init_flash_settings(struct aat1290_led *led,
+					 struct aat1290_led_settings *s)
+{
+	struct led_flash_setting *setting;
+
+	/* Init flash intensity setting */
+	setting = &s->torch_brightness;
+	/*
+	 * Torch current is adjustable in logarithmic fashion and thus
+	 * it is not possible to define fixed step in microamperes.
+	 * Instead led brightness levels are used to make possible
+	 * setting all the supported levels from V4L2 Flash sub-device.
+	 */
+	setting->min = 1;
+	setting->max = AAT1290_MAX_MM_CURR_PERCENT_0 -
+		       AAT1290_MAX_MM_CURR_PERCENT_100;
+	setting->step = 1;
+	setting->val = setting->max;
+
+	/* Init flash timeout setting */
+	setting = &s->flash_timeout;
+	setting->min = led->max_flash_tm / AAT1290_FLASH_TM_NUM_LEVELS;
+	setting->max = setting->min * AAT1290_FLASH_TM_NUM_LEVELS;
+	setting->step = setting->min;
+	setting->val = setting->max;
+}
+
+static const struct led_flash_ops flash_ops = {
+	.strobe_set = aat1290_led_flash_strobe_set,
+	.timeout_set = aat1290_led_flash_timeout_set,
+};
+
+static int aat1290_led_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *dev_node = pdev->dev.of_node;
+	struct aat1290_led *led;
+	struct led_classdev *led_cdev;
+	struct led_classdev_flash *fled_cdev;
+	struct aat1290_led_settings settings;
+	int flen_gpio, enset_gpio, ret;
+
+	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
+	if (!led)
+		return -ENOMEM;
+
+	led->pdev = pdev;
+	platform_set_drvdata(pdev, led);
+
+	if (!dev_node)
+		return -ENXIO;
+
+	flen_gpio = of_get_gpio(dev_node, 0);
+	if (gpio_is_valid(flen_gpio)) {
+		ret = devm_gpio_request_one(dev, flen_gpio, GPIOF_DIR_OUT,
+						"aat1290_flen");
+		if (ret < 0) {
+			dev_err(dev,
+				"failed to request GPIO %d, error %d\n",
+							flen_gpio, ret);
+			return ret;
+		}
+	}
+	led->flen_gpio = flen_gpio;
+
+	enset_gpio = of_get_gpio(dev_node, 1);
+	if (gpio_is_valid(enset_gpio)) {
+		ret = devm_gpio_request_one(dev, enset_gpio, GPIOF_DIR_OUT,
+						"aat1290_en_set");
+		if (ret < 0) {
+			dev_err(dev,
+				"failed to request GPIO %d, error %d\n",
+							enset_gpio, ret);
+			return ret;
+		}
+	}
+	led->en_set_gpio = enset_gpio;
+
+	ret = aat1290_led_parse_dt(led, &pdev->dev);
+	if (ret < 0)
+		return ret;
+
+	fled_cdev = &led->fled_cdev;
+
+	/* Init flash settings */
+	aat1290_init_flash_settings(led, &settings);
+
+	fled_cdev->timeout = settings.flash_timeout;
+
+	/* Init led class */
+	led_cdev = &fled_cdev->led_cdev;
+	led_cdev->name = led->label;
+	led_cdev->brightness_set = aat1290_led_brightness_set;
+	led_cdev->brightness_set_sync = aat1290_led_brightness_set_sync;
+	led_cdev->max_brightness = settings.torch_brightness.max;
+	led_cdev->flags |= LED_DEV_CAP_FLASH;
+
+	INIT_WORK(&led->work_brightness_set, aat1290_brightness_set_work);
+
+	fled_cdev->ops = &flash_ops;
+
+	/* Register in the LED subsystem. */
+	ret = led_classdev_flash_register(&pdev->dev, fled_cdev);
+	if (ret < 0)
+		return ret;
+
+	mutex_init(&led->lock);
+
+	return 0;
+}
+
+static int aat1290_led_remove(struct platform_device *pdev)
+{
+	struct aat1290_led *led = platform_get_drvdata(pdev);
+
+	led_classdev_flash_unregister(&led->fled_cdev);
+	cancel_work_sync(&led->work_brightness_set);
+
+	mutex_destroy(&led->lock);
+
+	return 0;
+}
+
+static struct of_device_id aat1290_led_dt_match[] = {
+	{.compatible = "skyworks,aat1290"},
+	{},
+};
+
+static struct platform_driver aat1290_led_driver = {
+	.probe		= aat1290_led_probe,
+	.remove		= aat1290_led_remove,
+	.driver		= {
+		.name	= "aat1290-led",
+		.owner	= THIS_MODULE,
+		.of_match_table = aat1290_led_dt_match,
+	},
+};
+
+module_platform_driver(aat1290_led_driver);
+
+MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
+MODULE_DESCRIPTION("Skyworks Current Regulator for Flash LEDs");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 10/19] leds: Add driver for AAT1290 current regulator
@ 2015-01-09 15:23     ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski

This patch adds a driver for the 1.5A Step-Up Current Regulator
for Flash LEDs. The device is programmed through a Skyworks proprietary
AS2Cwire serial digital interface.

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>
---
 drivers/leds/Kconfig        |    7 +
 drivers/leds/Makefile       |    1 +
 drivers/leds/leds-aat1290.c |  398 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 406 insertions(+)
 create mode 100644 drivers/leds/leds-aat1290.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index ff9c21b..d70fc7b 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -39,6 +39,13 @@ config LEDS_88PM860X
 	  This option enables support for on-chip LED drivers found on Marvell
 	  Semiconductor 88PM8606 PMIC.
 
+config LEDS_AAT1290
+	tristate "LED support for the AAT1290"
+	depends on LEDS_CLASS_FLASH
+	depends on OF
+	help
+	 This option enables support for the LEDs on the AAT1290.
+
 config LEDS_LM3530
 	tristate "LCD Backlight driver for LM3530"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 57ca62b..b802251 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_LEDS_TRIGGERS)		+= led-triggers.o
 
 # LED Platform Drivers
 obj-$(CONFIG_LEDS_88PM860X)		+= leds-88pm860x.o
+obj-$(CONFIG_LEDS_AAT1290)		+= leds-aat1290.o
 obj-$(CONFIG_LEDS_BD2802)		+= leds-bd2802.o
 obj-$(CONFIG_LEDS_LOCOMO)		+= leds-locomo.o
 obj-$(CONFIG_LEDS_LM3530)		+= leds-lm3530.o
diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c
new file mode 100644
index 0000000..0a3c9b4
--- /dev/null
+++ b/drivers/leds/leds-aat1290.c
@@ -0,0 +1,398 @@
+/*
+ *	LED Flash class driver for the AAT1290
+ *	1.5A Step-Up Current Regulator for Flash LEDs
+ *
+ *	Copyright (C) 2015, Samsung Electronics Co., Ltd.
+ *	Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/led-class-flash.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#define AAT1290_MOVIE_MODE_CURRENT_ADDR	17
+#define AAT1290_MAX_MM_CURR_PERCENT_0	16
+#define AAT1290_MAX_MM_CURR_PERCENT_100	1
+
+#define AAT1290_FLASH_SAFETY_TIMER_ADDR	18
+
+#define AAT1290_MOVIE_MODE_CONFIG_ADDR	19
+#define AAT1290_MOVIE_MODE_OFF		1
+#define AAT1290_MOVIE_MODE_ON		3
+
+#define AAT1290_MM_CURRENT_RATIO_ADDR	20
+#define AAT1290_MM_TO_FL_1_92		1
+#define AAT1290_MM_TO_FL_3_7		2
+#define AAT1290_MM_TO_FL_5_5		3
+#define AAT1290_MM_TO_FL_7_3		4
+#define AAT1290_MM_TO_FL_9		5
+#define AAT1290_MM_TO_FL_10_7		6
+#define AAT1290_MM_TO_FL_12_4		7
+#define AAT1290_MM_TO_FL_14		8
+#define AAT1290_MM_TO_FL_15_9		9
+#define AAT1290_MM_TO_FL_17_5		10
+#define AAT1290_MM_TO_FL_19_1		11
+#define AAT1290_MM_TO_FL_20_8		12
+#define AAT1290_MM_TO_FL_22_4		13
+#define AAT1290_MM_TO_FL_24		14
+#define AAT1290_MM_TO_FL_25_6		15
+#define AAT1290_MM_TO_FL_OFF		16
+
+#define AAT1290_LATCH_TIME_MIN_US	500
+#define AAT1290_LATCH_TIME_MAX_US	1000
+#define AAT1290_EN_SET_TICK_TIME_US	1
+#define AAT1290_FLEN_OFF_DELAY_TIME_US	10
+#define AAT1290_FLASH_TM_NUM_LEVELS	16
+
+struct aat1290_led_settings {
+	struct led_flash_setting torch_brightness;
+	struct led_flash_setting flash_brightness;
+	struct led_flash_setting flash_timeout;
+};
+
+struct aat1290_led {
+	struct platform_device *pdev;
+	struct mutex lock;
+
+	struct led_classdev_flash fled_cdev;
+
+	int flen_gpio;
+	int en_set_gpio;
+
+	u32 max_flash_tm;
+	bool movie_mode;
+
+	char *label;
+	unsigned int torch_brightness;
+	unsigned int flash_timeout;
+	struct work_struct work_brightness_set;
+};
+
+static struct aat1290_led *fled_cdev_to_led(
+				struct led_classdev_flash *fled_cdev)
+{
+	return container_of(fled_cdev, struct aat1290_led, fled_cdev);
+}
+
+static void aat1290_as2cwire_write(struct aat1290_led *led, int addr, int value)
+{
+	int i;
+
+	gpio_set_value(led->flen_gpio, 0);
+	gpio_set_value(led->en_set_gpio, 0);
+
+	udelay(AAT1290_FLEN_OFF_DELAY_TIME_US);
+
+	/* write address */
+	for (i = 0; i < addr; ++i) {
+		udelay(AAT1290_EN_SET_TICK_TIME_US);
+		gpio_set_value(led->en_set_gpio, 0);
+		udelay(AAT1290_EN_SET_TICK_TIME_US);
+		gpio_set_value(led->en_set_gpio, 1);
+	}
+
+	usleep_range(AAT1290_LATCH_TIME_MIN_US, AAT1290_LATCH_TIME_MAX_US);
+
+	/* write data */
+	for (i = 0; i < value; ++i) {
+		udelay(AAT1290_EN_SET_TICK_TIME_US);
+		gpio_set_value(led->en_set_gpio, 0);
+		udelay(AAT1290_EN_SET_TICK_TIME_US);
+		gpio_set_value(led->en_set_gpio, 1);
+	}
+
+	usleep_range(AAT1290_LATCH_TIME_MIN_US, AAT1290_LATCH_TIME_MAX_US);
+}
+
+static void aat1290_set_flash_safety_timer(struct aat1290_led *led,
+					unsigned int micro_sec)
+{
+	struct led_classdev_flash *fled_cdev = &led->fled_cdev;
+	struct led_flash_setting *flash_tm = &fled_cdev->timeout;
+	int flash_tm_reg = AAT1290_FLASH_TM_NUM_LEVELS -
+				(micro_sec / flash_tm->step) + 1;
+
+	aat1290_as2cwire_write(led, AAT1290_FLASH_SAFETY_TIMER_ADDR,
+							flash_tm_reg);
+}
+
+static void aat1290_brightness_set(struct aat1290_led *led,
+					enum led_brightness brightness)
+{
+	mutex_lock(&led->lock);
+
+	if (brightness == 0) {
+		gpio_set_value(led->flen_gpio, 0);
+		gpio_set_value(led->en_set_gpio, 0);
+		goto unlock;
+	}
+
+	if (!led->movie_mode) {
+		aat1290_as2cwire_write(led, AAT1290_MM_CURRENT_RATIO_ADDR,
+					AAT1290_MM_TO_FL_1_92);
+		led->movie_mode = true;
+	}
+
+	aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CURRENT_ADDR,
+				AAT1290_MAX_MM_CURR_PERCENT_0 - brightness);
+	aat1290_as2cwire_write(led, AAT1290_MOVIE_MODE_CONFIG_ADDR,
+				AAT1290_MOVIE_MODE_ON);
+unlock:
+	mutex_unlock(&led->lock);
+}
+
+/* LED subsystem callbacks */
+
+static void aat1290_brightness_set_work(struct work_struct *work)
+{
+	struct aat1290_led *led =
+		container_of(work, struct aat1290_led, work_brightness_set);
+
+	aat1290_brightness_set(led, led->torch_brightness);
+}
+
+static void aat1290_led_brightness_set(struct led_classdev *led_cdev,
+					enum led_brightness brightness)
+{
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
+
+	led->torch_brightness = brightness;
+	schedule_work(&led->work_brightness_set);
+}
+
+static int aat1290_led_brightness_set_sync(struct led_classdev *led_cdev,
+					enum led_brightness brightness)
+{
+	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+	struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
+
+	aat1290_brightness_set(led, brightness);
+
+	return 0;
+}
+
+static int aat1290_led_flash_strobe_set(struct led_classdev_flash *fled_cdev,
+					 bool state)
+
+{
+	struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
+	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+	struct led_flash_setting *timeout = &fled_cdev->timeout;
+
+	mutex_lock(&led->lock);
+
+	if (state == 0) {
+		gpio_set_value(led->flen_gpio, 0);
+		gpio_set_value(led->en_set_gpio, 0);
+		goto unlock;
+	}
+
+	aat1290_set_flash_safety_timer(led, timeout->val);
+
+	/*
+	 * To reenter movie mode after a flash event the part
+	 * must be cycled off and back on to reset the movie
+	 * mode and reprogrammed via the AS2Cwire. Therefore
+	 * the brightness value needs to be updated here to
+	 * reflect the actual state.
+	 */
+	led_cdev->brightness = 0;
+	led->movie_mode = false;
+
+	gpio_set_value(led->flen_gpio, 1);
+
+unlock:
+	mutex_unlock(&led->lock);
+
+	return 0;
+}
+
+static int aat1290_led_flash_timeout_set(struct led_classdev_flash *fled_cdev,
+						u32 timeout)
+{
+	/*
+	 * Don't do anything - flash timeout is cached in the led-class-flash
+	 * core and will be applied in the strobe_set op, as writing the
+	 * safety timer register spuriously turns the torch mode on.
+	 */
+
+	return 0;
+}
+
+static int aat1290_led_parse_dt(struct aat1290_led *led,
+				struct device *dev)
+{
+	int ret;
+
+	ret = of_property_read_string(dev->of_node, "label",
+				(const char **) &led->label);
+	if (ret < 0) {
+		dev_err(dev, "Error reading \"label\" DT property (%d)\n", ret);
+		return ret;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "flash-timeout-us",
+				&led->max_flash_tm);
+	if (ret < 0)
+		dev_err(dev, "Error reading \"flash-timeout-us\" DT property (%d)\n",
+			ret);
+
+	return ret;
+}
+
+static void aat1290_init_flash_settings(struct aat1290_led *led,
+					 struct aat1290_led_settings *s)
+{
+	struct led_flash_setting *setting;
+
+	/* Init flash intensity setting */
+	setting = &s->torch_brightness;
+	/*
+	 * Torch current is adjustable in logarithmic fashion and thus
+	 * it is not possible to define fixed step in microamperes.
+	 * Instead led brightness levels are used to make possible
+	 * setting all the supported levels from V4L2 Flash sub-device.
+	 */
+	setting->min = 1;
+	setting->max = AAT1290_MAX_MM_CURR_PERCENT_0 -
+		       AAT1290_MAX_MM_CURR_PERCENT_100;
+	setting->step = 1;
+	setting->val = setting->max;
+
+	/* Init flash timeout setting */
+	setting = &s->flash_timeout;
+	setting->min = led->max_flash_tm / AAT1290_FLASH_TM_NUM_LEVELS;
+	setting->max = setting->min * AAT1290_FLASH_TM_NUM_LEVELS;
+	setting->step = setting->min;
+	setting->val = setting->max;
+}
+
+static const struct led_flash_ops flash_ops = {
+	.strobe_set = aat1290_led_flash_strobe_set,
+	.timeout_set = aat1290_led_flash_timeout_set,
+};
+
+static int aat1290_led_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *dev_node = pdev->dev.of_node;
+	struct aat1290_led *led;
+	struct led_classdev *led_cdev;
+	struct led_classdev_flash *fled_cdev;
+	struct aat1290_led_settings settings;
+	int flen_gpio, enset_gpio, ret;
+
+	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
+	if (!led)
+		return -ENOMEM;
+
+	led->pdev = pdev;
+	platform_set_drvdata(pdev, led);
+
+	if (!dev_node)
+		return -ENXIO;
+
+	flen_gpio = of_get_gpio(dev_node, 0);
+	if (gpio_is_valid(flen_gpio)) {
+		ret = devm_gpio_request_one(dev, flen_gpio, GPIOF_DIR_OUT,
+						"aat1290_flen");
+		if (ret < 0) {
+			dev_err(dev,
+				"failed to request GPIO %d, error %d\n",
+							flen_gpio, ret);
+			return ret;
+		}
+	}
+	led->flen_gpio = flen_gpio;
+
+	enset_gpio = of_get_gpio(dev_node, 1);
+	if (gpio_is_valid(enset_gpio)) {
+		ret = devm_gpio_request_one(dev, enset_gpio, GPIOF_DIR_OUT,
+						"aat1290_en_set");
+		if (ret < 0) {
+			dev_err(dev,
+				"failed to request GPIO %d, error %d\n",
+							enset_gpio, ret);
+			return ret;
+		}
+	}
+	led->en_set_gpio = enset_gpio;
+
+	ret = aat1290_led_parse_dt(led, &pdev->dev);
+	if (ret < 0)
+		return ret;
+
+	fled_cdev = &led->fled_cdev;
+
+	/* Init flash settings */
+	aat1290_init_flash_settings(led, &settings);
+
+	fled_cdev->timeout = settings.flash_timeout;
+
+	/* Init led class */
+	led_cdev = &fled_cdev->led_cdev;
+	led_cdev->name = led->label;
+	led_cdev->brightness_set = aat1290_led_brightness_set;
+	led_cdev->brightness_set_sync = aat1290_led_brightness_set_sync;
+	led_cdev->max_brightness = settings.torch_brightness.max;
+	led_cdev->flags |= LED_DEV_CAP_FLASH;
+
+	INIT_WORK(&led->work_brightness_set, aat1290_brightness_set_work);
+
+	fled_cdev->ops = &flash_ops;
+
+	/* Register in the LED subsystem. */
+	ret = led_classdev_flash_register(&pdev->dev, fled_cdev);
+	if (ret < 0)
+		return ret;
+
+	mutex_init(&led->lock);
+
+	return 0;
+}
+
+static int aat1290_led_remove(struct platform_device *pdev)
+{
+	struct aat1290_led *led = platform_get_drvdata(pdev);
+
+	led_classdev_flash_unregister(&led->fled_cdev);
+	cancel_work_sync(&led->work_brightness_set);
+
+	mutex_destroy(&led->lock);
+
+	return 0;
+}
+
+static struct of_device_id aat1290_led_dt_match[] = {
+	{.compatible = "skyworks,aat1290"},
+	{},
+};
+
+static struct platform_driver aat1290_led_driver = {
+	.probe		= aat1290_led_probe,
+	.remove		= aat1290_led_remove,
+	.driver		= {
+		.name	= "aat1290-led",
+		.owner	= THIS_MODULE,
+		.of_match_table = aat1290_led_dt_match,
+	},
+};
+
+module_platform_driver(aat1290_led_driver);
+
+MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
+MODULE_DESCRIPTION("Skyworks Current Regulator for Flash LEDs");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 11/19] of: Add Skyworks Solutions, Inc. vendor prefix
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (9 preceding siblings ...)
       [not found] ` <1420816989-1808-1-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2015-01-09 15:23 ` Jacek Anaszewski
       [not found]   ` <1420816989-1808-12-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2015-01-09 15:23 ` [PATCH/RFC v10 12/19] DT: Add documentation for the Skyworks AAT1290 Jacek Anaszewski
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

Use "skyworks" as the vendor prefix for the Skyworks Solutions, Inc.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
---
 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index d8d18c0..b27fe1c 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -137,6 +137,7 @@ ricoh	Ricoh Co. Ltd.
 rockchip	Fuzhou Rockchip Electronics Co., Ltd
 samsung	Samsung Semiconductor
 sandisk	Sandisk Corporation
+skyworks	Skyworks Solutions, Inc.
 sbs	Smart Battery System
 schindler	Schindler
 seagate	Seagate Technology PLC
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 12/19] DT: Add documentation for the Skyworks AAT1290
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (10 preceding siblings ...)
  2015-01-09 15:23 ` [PATCH/RFC v10 11/19] of: Add Skyworks Solutions, Inc. vendor prefix Jacek Anaszewski
@ 2015-01-09 15:23 ` Jacek Anaszewski
  2015-01-09 18:58   ` Pavel Machek
  2015-01-09 15:23 ` [PATCH/RFC v10 13/19] exynos4-is: Add support for v4l2-flash subdevs Jacek Anaszewski
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

This patch adds device tree binding documentation for
1.5A Step-Up Current Regulator for Flash LEDs.

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: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
---
 .../devicetree/bindings/leds/leds-aat1290.txt      |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/leds-aat1290.txt

diff --git a/Documentation/devicetree/bindings/leds/leds-aat1290.txt b/Documentation/devicetree/bindings/leds/leds-aat1290.txt
new file mode 100644
index 0000000..880a21d
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-aat1290.txt
@@ -0,0 +1,17 @@
+* Skyworks Solutions, Inc. AAT1290 Current Regulator for Flash LEDs
+
+Required properties:
+
+- compatible : Must be "skyworks,aat1290".
+- gpios : Two gpio pins in order FLEN, EN/SET.
+- flash-timeout-us : Maximum flash timeout in microseconds -
+		     it can be calculated using following formula:
+		     T = 8.82 * 10^9 * Ct.
+
+Example:
+
+flash_led: led {
+	compatible = "skyworks,aat1290";
+	gpios = <&gpj1 1 0>, <&gpj1 2 0>;
+	flash-timeout-us = <1940000>;
+}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 13/19] exynos4-is: Add support for v4l2-flash subdevs
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (11 preceding siblings ...)
  2015-01-09 15:23 ` [PATCH/RFC v10 12/19] DT: Add documentation for the Skyworks AAT1290 Jacek Anaszewski
@ 2015-01-09 15:23 ` Jacek Anaszewski
  2015-01-09 19:06   ` Pavel Machek
  2015-01-09 15:23 ` [PATCH/RFC v10 14/19] v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control Jacek Anaszewski
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski

This patch adds suppport for external v4l2-flash devices.
The support includes parsing camera-flash DT property
and asynchronous subdevice registration.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 drivers/media/platform/exynos4-is/media-dev.c |   36 +++++++++++++++++++++++--
 drivers/media/platform/exynos4-is/media-dev.h |   13 ++++++++-
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index f315ef9..8dd0e5d 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -451,6 +451,25 @@ rpm_put:
 	return ret;
 }
 
+static void fimc_md_register_flash_entities(struct fimc_md *fmd)
+{
+	struct device_node *parent = fmd->pdev->dev.of_node;
+	struct device_node *np;
+	int i = 0;
+
+	do {
+		np = of_parse_phandle(parent, "flashes", i);
+		if (np) {
+			fmd->flash[fmd->num_flashes].asd.match_type =
+							V4L2_ASYNC_MATCH_OF;
+			fmd->flash[fmd->num_flashes].asd.match.of.node = np;
+			fmd->num_flashes++;
+			fmd->async_subdevs[fmd->num_sensors + i] =
+						&fmd->flash[i].asd;
+		}
+	} while (np && (++i < FIMC_MAX_FLASHES));
+}
+
 static int __of_get_csis_id(struct device_node *np)
 {
 	u32 reg = 0;
@@ -1275,6 +1294,15 @@ static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
 	struct fimc_sensor_info *si = NULL;
 	int i;
 
+	/* Register flash subdev if detected any */
+	for (i = 0; i < ARRAY_SIZE(fmd->flash); i++) {
+		if (fmd->flash[i].asd.match.of.node == subdev->dev->of_node) {
+			fmd->flash[i].subdev = subdev;
+			fmd->num_flashes++;
+			return 0;
+		}
+	}
+
 	/* Find platform data for this sensor subdev */
 	for (i = 0; i < ARRAY_SIZE(fmd->sensor); i++)
 		if (fmd->sensor[i].asd.match.of.node == subdev->dev->of_node)
@@ -1385,6 +1413,8 @@ static int fimc_md_probe(struct platform_device *pdev)
 		goto err_m_ent;
 	}
 
+	fimc_md_register_flash_entities(fmd);
+
 	mutex_unlock(&fmd->media_dev.graph_mutex);
 
 	ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode);
@@ -1401,12 +1431,14 @@ static int fimc_md_probe(struct platform_device *pdev)
 		goto err_attr;
 	}
 
-	if (fmd->num_sensors > 0) {
+	if (fmd->num_sensors > 0 || fmd->num_flashes > 0) {
 		fmd->subdev_notifier.subdevs = fmd->async_subdevs;
-		fmd->subdev_notifier.num_subdevs = fmd->num_sensors;
+		fmd->subdev_notifier.num_subdevs = fmd->num_sensors +
+							fmd->num_flashes;
 		fmd->subdev_notifier.bound = subdev_notifier_bound;
 		fmd->subdev_notifier.complete = subdev_notifier_complete;
 		fmd->num_sensors = 0;
+		fmd->num_flashes = 0;
 
 		ret = v4l2_async_notifier_register(&fmd->v4l2_dev,
 						&fmd->subdev_notifier);
diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h
index 0321454..feff9c8 100644
--- a/drivers/media/platform/exynos4-is/media-dev.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -34,6 +34,8 @@
 
 #define FIMC_MAX_SENSORS	4
 #define FIMC_MAX_CAMCLKS	2
+#define FIMC_MAX_FLASHES	2
+#define FIMC_MAX_ASYNC_SUBDEVS (FIMC_MAX_SENSORS + FIMC_MAX_FLASHES)
 #define DEFAULT_SENSOR_CLK_FREQ	24000000U
 
 /* LCD/ISP Writeback clocks (PIXELASYNCMx) */
@@ -93,6 +95,11 @@ struct fimc_sensor_info {
 	struct fimc_dev *host;
 };
 
+struct fimc_flash_info {
+	struct v4l2_subdev *subdev;
+	struct v4l2_async_subdev asd;
+};
+
 struct cam_clk {
 	struct clk_hw hw;
 	struct fimc_md *fmd;
@@ -104,6 +111,8 @@ struct cam_clk {
  * @csis: MIPI CSIS subdevs data
  * @sensor: array of registered sensor subdevs
  * @num_sensors: actual number of registered sensors
+ * @flash: array of registered flash subdevs
+ * @num_flashes: actual number of registered flashes
  * @camclk: external sensor clock information
  * @fimc: array of registered fimc devices
  * @fimc_is: fimc-is data structure
@@ -123,6 +132,8 @@ struct fimc_md {
 	struct fimc_csis_info csis[CSIS_MAX_ENTITIES];
 	struct fimc_sensor_info sensor[FIMC_MAX_SENSORS];
 	int num_sensors;
+	struct fimc_flash_info flash[FIMC_MAX_FLASHES];
+	int num_flashes;
 	struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS];
 	struct clk *wbclk[FIMC_MAX_WBCLKS];
 	struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS];
@@ -149,7 +160,7 @@ struct fimc_md {
 	} clk_provider;
 
 	struct v4l2_async_notifier subdev_notifier;
-	struct v4l2_async_subdev *async_subdevs[FIMC_MAX_SENSORS];
+	struct v4l2_async_subdev *async_subdevs[FIMC_MAX_ASYNC_SUBDEVS];
 
 	bool user_subdev_api;
 	spinlock_t slock;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 14/19] v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (12 preceding siblings ...)
  2015-01-09 15:23 ` [PATCH/RFC v10 13/19] exynos4-is: Add support for v4l2-flash subdevs Jacek Anaszewski
@ 2015-01-09 15:23 ` Jacek Anaszewski
       [not found]   ` <1420816989-1808-15-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2015-02-05 16:36   ` Sakari Ailus
  2015-01-09 15:23 ` [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices Jacek Anaszewski
                   ` (4 subsequent siblings)
  18 siblings, 2 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski,
	Hans Verkuil

Add V4L2_CID_FLASH_SYNC_STROBE control for determining
whether a flash device strobe has to be synchronized
with other flash leds controller by the same device.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Sakari Ailus <sakari.ailus@iki.fi>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
---
 Documentation/DocBook/media/v4l/controls.xml |    9 +++++++++
 drivers/media/v4l2-core/v4l2-ctrls.c         |    2 ++
 include/uapi/linux/v4l2-controls.h           |    1 +
 3 files changed, 12 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index e013e4b..8380b07e 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -4563,6 +4563,15 @@ interface and may change in the future.</para>
     	    after strobe during which another strobe will not be
     	    possible. This is a read-only control.</entry>
     	  </row>
+    	  <row>
+            <entry spanname="id"><constant>V4L2_CID_FLASH_SYNC_STROBE</constant></entry>
+            <entry>menu</entry>
+    	  </row>
+    	  <row>
+    	    <entry spanname="descr">Synchronized strobe: whether the flash
+	    should be strobed synchronously with the other one controlled
+	    by the same device.</entry>
+    	  </row>
     	  <row><entry></entry></row>
     	</tbody>
           </tgroup>
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 45c5b47..4bc7e00 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -846,6 +846,7 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_FLASH_FAULT:		return "Faults";
 	case V4L2_CID_FLASH_CHARGE:		return "Charge";
 	case V4L2_CID_FLASH_READY:		return "Ready to Strobe";
+	case V4L2_CID_FLASH_SYNC_STROBE:	return "Synchronize Strobe";
 
 	/* JPEG encoder controls */
 	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
@@ -1041,6 +1042,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_TUNE_DEEMPHASIS:
 	case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
 	case V4L2_CID_DETECT_MD_MODE:
+	case V4L2_CID_FLASH_SYNC_STROBE:
 		*type = V4L2_CTRL_TYPE_MENU;
 		break;
 	case V4L2_CID_LINK_FREQ:
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 661f119..5bce13d 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -833,6 +833,7 @@ enum v4l2_flash_strobe_source {
 
 #define V4L2_CID_FLASH_CHARGE			(V4L2_CID_FLASH_CLASS_BASE + 11)
 #define V4L2_CID_FLASH_READY			(V4L2_CID_FLASH_CLASS_BASE + 12)
+#define V4L2_CID_FLASH_SYNC_STROBE		(V4L2_CID_FLASH_CLASS_BASE + 13)
 
 
 /* JPEG-class control IDs */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (13 preceding siblings ...)
  2015-01-09 15:23 ` [PATCH/RFC v10 14/19] v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control Jacek Anaszewski
@ 2015-01-09 15:23 ` Jacek Anaszewski
  2015-01-09 20:54   ` Pavel Machek
  2015-02-05 17:59   ` Sakari Ailus
  2015-01-09 15:23 ` [PATCH/RFC v10 16/19] Documentation: leds: Add description of v4l2-flash sub-device Jacek Anaszewski
                   ` (3 subsequent siblings)
  18 siblings, 2 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski,
	Hans Verkuil

This patch adds helper functions for registering/unregistering
LED Flash class devices as V4L2 sub-devices. The functions should
be called from the LED subsystem device driver. In case the
support for V4L2 Flash sub-devices is disabled in the kernel
config the functions' empty versions will be used.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Sakari Ailus <sakari.ailus@iki.fi>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/Kconfig      |   11 +
 drivers/media/v4l2-core/Makefile     |    2 +
 drivers/media/v4l2-core/v4l2-flash.c |  581 ++++++++++++++++++++++++++++++++++
 include/media/v4l2-flash.h           |  139 ++++++++
 4 files changed, 733 insertions(+)
 create mode 100644 drivers/media/v4l2-core/v4l2-flash.c
 create mode 100644 include/media/v4l2-flash.h

diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index ba7e21a..f034f1a 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -44,6 +44,17 @@ config V4L2_MEM2MEM_DEV
         tristate
         depends on VIDEOBUF2_CORE
 
+# Used by LED subsystem flash drivers
+config V4L2_FLASH_LED_CLASS
+	tristate "Enable support for Flash sub-devices"
+	depends on VIDEO_V4L2_SUBDEV_API
+	depends on LEDS_CLASS_FLASH
+	---help---
+	  Say Y here to enable support for Flash sub-devices, which allow
+	  to control LED class devices with use of V4L2 Flash controls.
+
+	  When in doubt, say N.
+
 # Used by drivers that need Videobuf modules
 config VIDEOBUF_GEN
 	tristate
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index 63d29f2..44e858c 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -22,6 +22,8 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 
 obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
 
+obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash.o
+
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
 obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
diff --git a/drivers/media/v4l2-core/v4l2-flash.c b/drivers/media/v4l2-core/v4l2-flash.c
new file mode 100644
index 0000000..3fd6a08
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-flash.c
@@ -0,0 +1,581 @@
+/*
+ * V4L2 Flash LED sub-device registration helpers.
+ *
+ *	Copyright (C) 2015 Samsung Electronics Co., Ltd
+ *	Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation."
+ */
+
+#include <linux/led-class-flash.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <media/v4l2-flash.h>
+
+#define has_flash_op(v4l2_flash, op)			\
+	(v4l2_flash && v4l2_flash->ops->op)
+
+#define call_flash_op(v4l2_flash, op, args...)		\
+		(has_flash_op(v4l2_flash, op) ?		\
+			v4l2_flash->ops->op(args) :	\
+			-EINVAL)
+
+static inline enum led_brightness v4l2_flash_intensity_to_led_brightness(
+					struct v4l2_ctrl **ctrls,
+					enum ctrl_init_data_id cdata_id,
+					s32 intensity)
+{
+	struct v4l2_ctrl *ctrl = ctrls[cdata_id];
+	s64 __intensity = intensity - ctrl->minimum;
+
+	do_div(__intensity, ctrl->step);
+
+	/*
+	 * Indicator leds, unlike torch leds, are turned on/off basing on
+	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
+	 * Therefore it must be possible to set it to 0 level which in
+	 * the LED subsystem reflects LED_OFF state.
+	 */
+	if (cdata_id != INDICATOR_INTENSITY)
+		++__intensity;
+
+	return __intensity;
+}
+
+static inline s32 v4l2_flash_led_brightness_to_intensity(
+					struct v4l2_ctrl **ctrls,
+					enum ctrl_init_data_id cdata_id,
+					enum led_brightness brightness)
+{
+	struct v4l2_ctrl *ctrl = ctrls[cdata_id];
+
+	/*
+	 * Indicator leds, unlike torch leds, are turned on/off basing on
+	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
+	 * Do not decrement brightness read from the LED subsystem for
+	 * indicator led as it may equal 0. For torch leds this function
+	 * is called only when V4L2_FLASH_LED_MODE_TORCH is set and the
+	 * brightness read is guaranteed to be greater than 0. In the mode
+	 * V4L2_FLASH_LED_MODE_NONE the cached torch intensity value is used.
+	 */
+	if (cdata_id != INDICATOR_INTENSITY)
+		--brightness;
+
+	return (brightness * ctrl->step) + ctrl->minimum;
+}
+
+static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c)
+{
+	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 v4l2_ctrl **ctrls = v4l2_flash->ctrls;
+	bool is_strobing;
+	int ret;
+
+	switch (c->id) {
+	case V4L2_CID_FLASH_TORCH_INTENSITY:
+		/*
+		 * Update torch brightness only if in TORCH_MODE.
+		 * In other modes torch led is turned off, which
+		 * would spuriously inform the user space that
+		 * V4L2_CID_FLASH_TORCH_INTENSITY control setting
+		 * has changed.
+		 */
+		if (ctrls[LED_MODE]->val == V4L2_FLASH_LED_MODE_TORCH) {
+			ret = led_update_brightness(led_cdev);
+			if (ret < 0)
+				return ret;
+			c->val = v4l2_flash_led_brightness_to_intensity(
+							ctrls, TORCH_INTENSITY,
+							led_cdev->brightness);
+		}
+		return 0;
+	case V4L2_CID_FLASH_INDICATOR_INTENSITY:
+		ret = led_update_brightness(led_cdev);
+		if (ret < 0)
+			return ret;
+		c->val = v4l2_flash_led_brightness_to_intensity(
+						ctrls, INDICATOR_INTENSITY,
+						led_cdev->brightness);
+		return 0;
+	case V4L2_CID_FLASH_INTENSITY:
+		ret = led_update_flash_brightness(fled_cdev);
+		if (ret < 0)
+			return ret;
+		/* no conversion is needed */
+		c->val = fled_cdev->brightness.val;
+		return 0;
+	case V4L2_CID_FLASH_STROBE_STATUS:
+		ret = led_get_flash_strobe(fled_cdev, &is_strobing);
+		if (ret < 0)
+			return ret;
+		c->val = is_strobing;
+		return 0;
+	case V4L2_CID_FLASH_FAULT:
+		/* led faults map directly to V4L2 flash faults */
+		return led_get_flash_fault(fled_cdev, &c->val);
+	case V4L2_CID_FLASH_SYNC_STROBE:
+		c->val = fled_cdev->sync_led_id;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
+{
+	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 v4l2_ctrl **ctrls = v4l2_flash->ctrls;
+	enum led_brightness brightness;
+	bool external_strobe;
+	int ret = 0;
+
+	switch (c->id) {
+	case V4L2_CID_FLASH_LED_MODE:
+		switch (c->val) {
+		case V4L2_FLASH_LED_MODE_NONE:
+			led_set_brightness(led_cdev, LED_OFF);
+			return led_set_flash_strobe(fled_cdev, false);
+		case V4L2_FLASH_LED_MODE_FLASH:
+			/* Turn the torch LED off */
+			led_set_brightness(led_cdev, LED_OFF);
+			external_strobe = (ctrls[STROBE_SOURCE]->val ==
+					V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
+
+			if (has_flash_op(v4l2_flash, external_strobe_set))
+				ret = call_flash_op(v4l2_flash,
+						external_strobe_set, v4l2_flash,
+						external_strobe);
+			return ret;
+		case V4L2_FLASH_LED_MODE_TORCH:
+			/* Stop flash strobing */
+			ret = led_set_flash_strobe(fled_cdev, false);
+			if (ret < 0)
+				return ret;
+
+			brightness =
+				v4l2_flash_intensity_to_led_brightness(
+						ctrls, TORCH_INTENSITY,
+						ctrls[TORCH_INTENSITY]->val);
+			led_set_brightness(led_cdev, brightness);
+			return 0;
+		}
+		break;
+	case V4L2_CID_FLASH_STROBE_SOURCE:
+		external_strobe = (c->val == V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
+
+		return call_flash_op(v4l2_flash, external_strobe_set,
+					v4l2_flash, external_strobe);
+	case V4L2_CID_FLASH_STROBE:
+		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH ||
+		    ctrls[STROBE_SOURCE]->val !=
+					V4L2_FLASH_STROBE_SOURCE_SOFTWARE)
+			return -EINVAL;
+		return led_set_flash_strobe(fled_cdev, true);
+	case V4L2_CID_FLASH_STROBE_STOP:
+		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH ||
+		    ctrls[STROBE_SOURCE]->val !=
+					V4L2_FLASH_STROBE_SOURCE_SOFTWARE)
+			return -EINVAL;
+		return led_set_flash_strobe(fled_cdev, false);
+	case V4L2_CID_FLASH_TIMEOUT:
+		/* no conversion is needed */
+		return led_set_flash_timeout(fled_cdev, c->val);
+	case V4L2_CID_FLASH_INTENSITY:
+		/* no conversion is needed */
+		return led_set_flash_brightness(fled_cdev, c->val);
+	case V4L2_CID_FLASH_INDICATOR_INTENSITY:
+		brightness = v4l2_flash_intensity_to_led_brightness(
+						ctrls, INDICATOR_INTENSITY,
+						c->val);
+		led_set_brightness(led_cdev, brightness);
+		return 0;
+	case V4L2_CID_FLASH_TORCH_INTENSITY:
+		/*
+		 * If not in MODE_TORCH don't call led-class brightness_set
+		 * op, as it would result in turning the torch led on.
+		 * Instead the value is cached only and will be written
+		 * to the device upon transition to MODE_TORCH.
+		 */
+		if (ctrls[LED_MODE]->val == V4L2_FLASH_LED_MODE_TORCH) {
+			brightness =
+				v4l2_flash_intensity_to_led_brightness(
+							ctrls, TORCH_INTENSITY,
+							c->val);
+			led_set_brightness(led_cdev, brightness);
+		}
+		return 0;
+	case V4L2_CID_FLASH_SYNC_STROBE:
+		fled_cdev->sync_led_id = c->val;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops = {
+	.g_volatile_ctrl = v4l2_flash_g_volatile_ctrl,
+	.s_ctrl = v4l2_flash_s_ctrl,
+};
+
+static void fill_ctrl_init_data(struct v4l2_flash *v4l2_flash,
+			  struct v4l2_flash_ctrl_config *flash_ctrl_cfg,
+			  struct v4l2_flash_ctrl_data *ctrl_init_data)
+{
+	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
+	const struct led_flash_ops *fled_cdev_ops = fled_cdev->ops;
+	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+	struct v4l2_ctrl_config *ctrl_cfg;
+	u32 mask;
+	s64 max;
+
+	/* Init FLASH_FAULT ctrl data */
+	if (flash_ctrl_cfg->flash_faults) {
+		ctrl_init_data[FLASH_FAULT].supported = true;
+		ctrl_cfg = &ctrl_init_data[FLASH_FAULT].config;
+		ctrl_cfg->id = V4L2_CID_FLASH_FAULT;
+		ctrl_cfg->max = flash_ctrl_cfg->flash_faults;
+		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
+				  V4L2_CTRL_FLAG_READ_ONLY;
+	}
+
+	/* Init INDICATOR_INTENSITY ctrl data */
+	if (flash_ctrl_cfg->indicator_led) {
+		ctrl_init_data[INDICATOR_INTENSITY].supported = true;
+		ctrl_init_data[INDICATOR_INTENSITY].config =
+						flash_ctrl_cfg->intensity;
+		ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config;
+		ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
+		ctrl_cfg->min = 0;
+		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
+
+		/* Indicator LED can have only faults and intensity controls. */
+		return;
+	}
+
+	/* Init FLASH_LED_MODE ctrl data */
+	mask = 1 << V4L2_FLASH_LED_MODE_NONE |
+	       1 << V4L2_FLASH_LED_MODE_TORCH;
+	if (led_cdev->flags & LED_DEV_CAP_FLASH)
+		mask |= 1 << V4L2_FLASH_LED_MODE_FLASH;
+
+	ctrl_init_data[LED_MODE].supported = true;
+	ctrl_cfg = &ctrl_init_data[LED_MODE].config;
+	ctrl_cfg->id = V4L2_CID_FLASH_LED_MODE;
+	ctrl_cfg->max = V4L2_FLASH_LED_MODE_TORCH;
+	ctrl_cfg->menu_skip_mask = ~mask;
+	ctrl_cfg->def = V4L2_FLASH_LED_MODE_NONE;
+	ctrl_cfg->flags = 0;
+
+	/* Init TORCH_INTENSITY ctrl data */
+	ctrl_init_data[TORCH_INTENSITY].supported = true;
+	ctrl_init_data[TORCH_INTENSITY].config = flash_ctrl_cfg->intensity;
+	ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config;
+	ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY;
+	ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
+
+	if (!(led_cdev->flags & LED_DEV_CAP_FLASH))
+		return;
+
+	/* Init FLASH_STROBE_SOURCE ctrl data */
+	mask = 1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
+	if (flash_ctrl_cfg->has_external_strobe) {
+		mask |= 1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
+		max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
+	} else {
+		max = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
+	}
+
+	ctrl_init_data[STROBE_SOURCE].supported = true;
+	ctrl_cfg = &ctrl_init_data[STROBE_SOURCE].config;
+	ctrl_cfg->id = V4L2_CID_FLASH_STROBE_SOURCE;
+	ctrl_cfg->max = max;
+	ctrl_cfg->menu_skip_mask = ~mask;
+	ctrl_cfg->def = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
+
+	/* Init FLASH_STROBE ctrl data */
+	ctrl_init_data[FLASH_STROBE].supported = true;
+	ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config;
+	ctrl_cfg->id = V4L2_CID_FLASH_STROBE;
+
+	/* Init STROBE_STOP ctrl data */
+	ctrl_init_data[STROBE_STOP].supported = true;
+	ctrl_cfg = &ctrl_init_data[STROBE_STOP].config;
+	ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STOP;
+
+	/* Init STROBE_STATUS ctrl data */
+	if (fled_cdev_ops->strobe_get) {
+		ctrl_init_data[STROBE_STATUS].supported = true;
+		ctrl_cfg = &ctrl_init_data[STROBE_STATUS].config;
+		ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STATUS;
+		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
+				  V4L2_CTRL_FLAG_READ_ONLY;
+	}
+
+	/* Init FLASH_TIMEOUT ctrl data */
+	if (fled_cdev_ops->timeout_set) {
+		ctrl_init_data[FLASH_TIMEOUT].supported = true;
+		ctrl_init_data[FLASH_TIMEOUT].config =
+					flash_ctrl_cfg->flash_timeout;
+		ctrl_cfg = &ctrl_init_data[FLASH_TIMEOUT].config;
+		ctrl_cfg->id = V4L2_CID_FLASH_TIMEOUT;
+		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
+	}
+
+	/* Init FLASH_INTENSITY ctrl data */
+	if (fled_cdev_ops->flash_brightness_set) {
+		ctrl_init_data[FLASH_INTENSITY].supported = true;
+		ctrl_init_data[FLASH_INTENSITY].config =
+					flash_ctrl_cfg->flash_intensity;
+		ctrl_cfg = &ctrl_init_data[FLASH_INTENSITY].config;
+		ctrl_cfg->id = V4L2_CID_FLASH_INTENSITY;
+		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
+	}
+}
+
+static int v4l2_flash_init_sync_strobe_menu(struct v4l2_flash *v4l2_flash)
+{
+	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
+	struct v4l2_ctrl *ctrl;
+	int i = 0;
+
+	v4l2_flash->sync_strobe_menu =
+			devm_kcalloc(fled_cdev->led_cdev.dev->parent,
+					fled_cdev->num_sync_leds + 1,
+					sizeof(*fled_cdev),
+					GFP_KERNEL);
+
+	if (!v4l2_flash->sync_strobe_menu)
+		return -ENOMEM;
+
+	v4l2_flash->sync_strobe_menu[0] = "none";
+
+	for (i = 0; i < fled_cdev->num_sync_leds; ++i)
+		v4l2_flash->sync_strobe_menu[i + 1] =
+				(char *) fled_cdev->sync_leds[i]->led_cdev.name;
+
+	ctrl = v4l2_ctrl_new_std_menu_items(
+		&v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
+		V4L2_CID_FLASH_SYNC_STROBE,
+		fled_cdev->num_sync_leds,
+		0, 0,
+		(const char * const *) v4l2_flash->sync_strobe_menu);
+
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+	return 0;
+}
+
+static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash,
+				struct v4l2_flash_ctrl_config *flash_ctrl_cfg)
+
+{
+	struct led_classdev *led_cdev = &v4l2_flash->fled_cdev->led_cdev;
+	struct v4l2_flash_ctrl_data *ctrl_init_data;
+	struct v4l2_ctrl *ctrl;
+	struct v4l2_ctrl_config *ctrl_cfg;
+	int i, ret, num_ctrls = 0;
+
+	/* allocate memory dynamically so as not to exceed stack frame size */
+	ctrl_init_data = kcalloc(NUM_FLASH_CTRLS, sizeof(*ctrl_init_data),
+					GFP_KERNEL);
+	if (!ctrl_init_data)
+		return -ENOMEM;
+
+	memset(ctrl_init_data, 0, sizeof(*ctrl_init_data));
+
+	fill_ctrl_init_data(v4l2_flash, flash_ctrl_cfg, ctrl_init_data);
+
+	for (i = 0; i < NUM_FLASH_CTRLS; ++i)
+		if (ctrl_init_data[i].supported)
+			++num_ctrls;
+
+	v4l2_ctrl_handler_init(&v4l2_flash->hdl, num_ctrls);
+
+	for (i = 0; i < NUM_FLASH_CTRLS; ++i) {
+		ctrl_cfg = &ctrl_init_data[i].config;
+		if (!ctrl_init_data[i].supported)
+			continue;
+
+		if (ctrl_cfg->id == V4L2_CID_FLASH_LED_MODE ||
+		    ctrl_cfg->id == V4L2_CID_FLASH_STROBE_SOURCE)
+			ctrl = v4l2_ctrl_new_std_menu(&v4l2_flash->hdl,
+						&v4l2_flash_ctrl_ops,
+						ctrl_cfg->id,
+						ctrl_cfg->max,
+						ctrl_cfg->menu_skip_mask,
+						ctrl_cfg->def);
+		else
+			ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl,
+						&v4l2_flash_ctrl_ops,
+						ctrl_cfg->id,
+						ctrl_cfg->min,
+						ctrl_cfg->max,
+						ctrl_cfg->step,
+						ctrl_cfg->def);
+
+		if (ctrl)
+			ctrl->flags |= ctrl_cfg->flags;
+
+		if (i <= STROBE_SOURCE)
+			v4l2_flash->ctrls[i] = ctrl;
+	}
+
+	kfree(ctrl_init_data);
+
+	if (led_cdev->flags & LED_DEV_CAP_SYNC_STROBE) {
+		ret = v4l2_flash_init_sync_strobe_menu(v4l2_flash);
+		if (ret < 0)
+			goto error_free_handler;
+	}
+
+	if (v4l2_flash->hdl.error) {
+		ret = v4l2_flash->hdl.error;
+		goto error_free_handler;
+	}
+
+	v4l2_ctrl_handler_setup(&v4l2_flash->hdl);
+
+	v4l2_flash->sd.ctrl_handler = &v4l2_flash->hdl;
+
+	return 0;
+
+error_free_handler:
+	v4l2_ctrl_handler_free(&v4l2_flash->hdl);
+	return ret;
+}
+
+/*
+ * V4L2 subdev internal operations
+ */
+
+static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	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;
+	int ret = 0;
+
+	mutex_lock(&led_cdev->led_access);
+
+	if (!v4l2_fh_is_singular(&fh->vfh)) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	led_sysfs_disable(led_cdev);
+
+unlock:
+	mutex_unlock(&led_cdev->led_access);
+	return ret;
+}
+
+static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	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;
+	int ret = 0;
+
+	mutex_lock(&led_cdev->led_access);
+
+	if (has_flash_op(v4l2_flash, external_strobe_set))
+		ret = call_flash_op(v4l2_flash, external_strobe_set,
+				v4l2_flash, false);
+	led_sysfs_enable(led_cdev);
+
+	mutex_unlock(&led_cdev->led_access);
+
+	return ret;
+}
+
+static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = {
+	.open = v4l2_flash_open,
+	.close = v4l2_flash_close,
+};
+
+static const struct v4l2_subdev_core_ops v4l2_flash_core_ops = {
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static const struct v4l2_subdev_ops v4l2_flash_subdev_ops = {
+	.core = &v4l2_flash_core_ops,
+};
+
+struct v4l2_flash *v4l2_flash_init(struct led_classdev_flash *fled_cdev,
+				   const struct v4l2_flash_ops *ops,
+				   struct v4l2_flash_ctrl_config *config)
+{
+	struct v4l2_flash *v4l2_flash;
+	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	if (!fled_cdev || !ops || !config)
+		return ERR_PTR(-EINVAL);
+
+	v4l2_flash = kzalloc(sizeof(*v4l2_flash), GFP_KERNEL);
+	if (!v4l2_flash)
+		return ERR_PTR(-ENOMEM);
+
+	sd = &v4l2_flash->sd;
+	v4l2_flash->fled_cdev = fled_cdev;
+	v4l2_flash->ops = ops;
+	sd->dev = led_cdev->dev;
+	v4l2_subdev_init(sd, &v4l2_flash_subdev_ops);
+	sd->internal_ops = &v4l2_flash_subdev_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(sd->name, sizeof(sd->name), led_cdev->name);
+
+	ret = v4l2_flash_init_controls(v4l2_flash, config);
+	if (ret < 0)
+		goto err_init_controls;
+
+	ret = media_entity_init(&sd->entity, 0, NULL, 0);
+	if (ret < 0)
+		goto err_init_entity;
+
+	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret < 0)
+		goto err_init_entity;
+
+	return v4l2_flash;
+
+err_init_entity:
+	media_entity_cleanup(&sd->entity);
+err_init_controls:
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	kfree(v4l2_flash);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(v4l2_flash_init);
+
+void v4l2_flash_release(struct v4l2_flash *v4l2_flash)
+{
+	struct v4l2_subdev *sd = &v4l2_flash->sd;
+
+	if (!v4l2_flash)
+		return;
+
+	v4l2_async_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	kfree(v4l2_flash);
+}
+EXPORT_SYMBOL_GPL(v4l2_flash_release);
+
+MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
+MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
+MODULE_LICENSE("GPL v2");
diff --git a/include/media/v4l2-flash.h b/include/media/v4l2-flash.h
new file mode 100644
index 0000000..404b5a8
--- /dev/null
+++ b/include/media/v4l2-flash.h
@@ -0,0 +1,139 @@
+/*
+ * V4L2 Flash LED sub-device registration helpers.
+ *
+ *	Copyright (C) 2015 Samsung Electronics Co., Ltd
+ *	Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation."
+ */
+
+#ifndef _V4L2_FLASH_H
+#define _V4L2_FLASH_H
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+struct led_classdev_flash;
+struct led_classdev;
+struct v4l2_flash;
+enum led_brightness;
+
+enum ctrl_init_data_id {
+	LED_MODE,
+	TORCH_INTENSITY,
+	INDICATOR_INTENSITY,
+	STROBE_SOURCE,
+	FLASH_STROBE,
+	STROBE_STOP,
+	STROBE_STATUS,
+	FLASH_TIMEOUT,
+	FLASH_INTENSITY,
+	FLASH_FAULT,
+	SYNC_STROBE,
+	NUM_FLASH_CTRLS,
+};
+
+/*
+ * struct v4l2_flash_ctrl_data - flash control initialization data -
+ *				 filled basing on the features declared
+ *				 by the LED Flash class driver
+ * @config:	initialization data for a control
+ * @supported:	indicates whether a control is supported
+ *		by the LED Flash class driver
+ */
+struct v4l2_flash_ctrl_data {
+	struct v4l2_ctrl_config config;
+	bool supported;
+};
+
+struct v4l2_flash_ops {
+	/* setup strobing the flash by hardware pin state assertion */
+	int (*external_strobe_set)(struct v4l2_flash *v4l2_flash,
+					bool enable);
+};
+
+/**
+ * struct v4l2_flash_ctrl_config - V4L2 Flash controls initialization data
+ * @intensity:			constraints for the led in a non-flash mode
+ * @flash_intensity:		V4L2_CID_FLASH_INTENSITY settings constraints
+ * @flash_timeout:		V4L2_CID_FLASH_TIMEOUT constraints
+ * @flash_faults:		possible flash faults
+ * @has_external_strobe:	external strobe capability
+ * @indicator_led:		signifies that a led is of indicator type
+ */
+struct v4l2_flash_ctrl_config {
+	struct v4l2_ctrl_config intensity;
+	struct v4l2_ctrl_config flash_intensity;
+	struct v4l2_ctrl_config flash_timeout;
+	u32 flash_faults;
+	bool has_external_strobe:1;
+	bool indicator_led:1;
+};
+
+/**
+ * struct v4l2_flash - Flash sub-device context
+ * @fled_cdev:		LED Flash Class device controlled by this sub-device
+ * @ops:		V4L2 specific flash ops
+ * @sd:			V4L2 sub-device
+ * @hdl:		flash controls handler
+ * @ctrls:		array of pointers to controls, whose values define
+ *			the sub-device state
+ * @sync_strobe_menu	leds available for flash strobe synchronization
+ */
+struct v4l2_flash {
+	struct led_classdev_flash *fled_cdev;
+	const struct v4l2_flash_ops *ops;
+
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_ctrl *ctrls[STROBE_SOURCE + 1];
+	char **sync_strobe_menu;
+};
+
+static inline struct v4l2_flash *v4l2_subdev_to_v4l2_flash(
+							struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct v4l2_flash, sd);
+}
+
+static inline struct v4l2_flash *v4l2_ctrl_to_v4l2_flash(struct v4l2_ctrl *c)
+{
+	return container_of(c->handler, struct v4l2_flash, hdl);
+}
+
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+/**
+ * v4l2_flash_init - initialize V4L2 flash led sub-device
+ * @fled_cdev:	the LED Flash Class device to wrap
+ * @flash_ops:	V4L2 Flash device ops
+ * @config:	initialization data for V4L2 Flash controls
+ *
+ * Create V4L2 subdev 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_init(struct led_classdev_flash *fled_cdev,
+				   const struct v4l2_flash_ops *ops,
+				   struct v4l2_flash_ctrl_config *config);
+
+/**
+ * v4l2_flash_release - release V4L2 Flash sub-device
+ * @flash: the V4L2 Flash device to release
+ *
+ * Release V4L2 flash led subdev.
+ */
+void v4l2_flash_release(struct v4l2_flash *v4l2_flash);
+
+#else
+#define v4l2_flash_init(fled_cdev, ops, config) (NULL)
+#define v4l2_flash_release(v4l2_flash)
+#endif /* CONFIG_V4L2_FLASH_LED_CLASS */
+
+#endif /* _V4L2_FLASH_H */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 16/19] Documentation: leds: Add description of v4l2-flash sub-device
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (14 preceding siblings ...)
  2015-01-09 15:23 ` [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices Jacek Anaszewski
@ 2015-01-09 15:23 ` Jacek Anaszewski
  2015-01-09 20:57   ` Pavel Machek
  2015-01-09 15:23 ` [PATCH/RFC v10 17/19] DT: Add documentation for exynos4-is 'flashes' property Jacek Anaszewski
                   ` (2 subsequent siblings)
  18 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski

This patch extends LED Flash class documention by
the description of interactions with v4l2-flash sub-device.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Cc: Bryan Wu <cooloney@gmail.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
---
 Documentation/leds/leds-class-flash.txt |   13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/Documentation/leds/leds-class-flash.txt b/Documentation/leds/leds-class-flash.txt
index d80096b..2f38627 100644
--- a/Documentation/leds/leds-class-flash.txt
+++ b/Documentation/leds/leds-class-flash.txt
@@ -55,3 +55,16 @@ Following sysfs attributes are exposed for controlling flash led devices:
 			  upper limit
 
 		Flash faults are cleared, if possible, by reading the attribute.
+
+A LED subsystem driver can be controlled also from the level of VideoForLinux2
+subsystem. In order to enable this CONFIG_V4L2_FLASH_LED_CLASS symbol has to
+be defined in the kernel config. The driver must call the v4l2_flash_init
+function to get registered in the V4L2 subsystem. On remove the
+v4l2_flash_release function has to be called (see <media/v4l2-flash.h>).
+
+After proper initialization a V4L2 Flash sub-device is created. The sub-device
+exposes a number of V4L2 controls, which allow for controlling a LED Flash class
+device with use of its internal kernel API.
+Opening the V4L2 Flash sub-device makes the LED subsystem sysfs interface
+unavailable. The interface is re-enabled after the V4L2 Flash sub-device
+is closed.
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 17/19] DT: Add documentation for exynos4-is 'flashes' property
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (15 preceding siblings ...)
  2015-01-09 15:23 ` [PATCH/RFC v10 16/19] Documentation: leds: Add description of v4l2-flash sub-device Jacek Anaszewski
@ 2015-01-09 15:23 ` Jacek Anaszewski
  2015-01-09 20:57   ` Pavel Machek
  2015-01-21 16:32   ` Sylwester Nawrocki
  2015-01-09 15:23 ` [PATCH/RFC v10 18/19] leds: max77693: add support for V4L2 Flash sub-device Jacek Anaszewski
  2015-01-09 15:23 ` [PATCH/RFC v10 19/19] leds: aat1290: " Jacek Anaszewski
  18 siblings, 2 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

This patch adds a description of 'flashes' property
to the samsung-fimc.txt.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Sylwester Nawrocki <s.nawrocki@samsung.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
---
 .../devicetree/bindings/media/samsung-fimc.txt     |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt
index 922d6f8..22a6b2f 100644
--- a/Documentation/devicetree/bindings/media/samsung-fimc.txt
+++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt
@@ -40,6 +40,12 @@ should be inactive. For the "active-a" state the camera port A must be activated
 and the port B deactivated and for the state "active-b" it should be the other
 way around.
 
+Optional properties:
+
+- flashes - Array of phandles to flash LED devices, or their sub-nodes
+	    representing sub-leds.
+	    (see Documentation/devicetree/bindings/leds/common.txt)
+
 The 'camera' node must include at least one 'fimc' child node.
 
 
@@ -166,6 +172,7 @@ Example:
 		clock-output-names = "cam_a_clkout", "cam_b_clkout";
 		pinctrl-names = "default";
 		pinctrl-0 = <&cam_port_a_clk_active>;
+		flashes = <&camera_flash>, <&system_torch>;
 		status = "okay";
 		#address-cells = <1>;
 		#size-cells = <1>;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 18/19] leds: max77693: add support for V4L2 Flash sub-device
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (16 preceding siblings ...)
  2015-01-09 15:23 ` [PATCH/RFC v10 17/19] DT: Add documentation for exynos4-is 'flashes' property Jacek Anaszewski
@ 2015-01-09 15:23 ` Jacek Anaszewski
  2015-01-09 20:59   ` Pavel Machek
  2015-01-09 15:23 ` [PATCH/RFC v10 19/19] leds: aat1290: " Jacek Anaszewski
  18 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski,
	Sakari Ailus

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@linux.intel.com>
---
 drivers/leds/leds-max77693.c |  151 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 142 insertions(+), 9 deletions(-)

diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
index 3ba07c4..ef35abb 100644
--- a/drivers/leds/leds-max77693.c
+++ b/drivers/leds/leds-max77693.c
@@ -21,6 +21,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))
@@ -52,6 +53,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;
@@ -624,6 +627,32 @@ unlock:
 	return ret;
 }
 
+#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;
+}
+#else
+#define max77693_led_external_strobe_set(v4l2_flash, enable) (NULL)
+#endif
+
 static int max77693_led_flash_fault_get(
 				struct led_classdev_flash *fled_cdev,
 				u32 *fault)
@@ -689,7 +718,8 @@ static int max77693_led_flash_timeout_set(
 }
 
 static int max77693_led_parse_dt(struct max77693_led_device *led,
-				 struct device_node *node)
+				 struct device_node *node,
+				 struct device_node **sub_nodes)
 {
 	struct max77693_led_config_data *cfg = led->cfg_data;
 	struct max77693_sub_led *sub_leds = led->sub_leds;
@@ -727,6 +757,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;
 
 		ret = of_property_read_string(child_node, "label",
@@ -812,7 +849,8 @@ static void max77693_led_validate_configuration(struct max77693_led_device *led)
 				MAX_FLASH1_VSYS_MAX, MAX_FLASH1_VSYS_STEP);
 }
 
-static int max77693_led_get_configuration(struct max77693_led_device *led)
+static int max77693_led_get_configuration(struct max77693_led_device *led,
+					  struct device_node **sub_nodes)
 {
 	struct device *dev = &led->pdev->dev;
 	int ret;
@@ -824,7 +862,7 @@ static int max77693_led_get_configuration(struct max77693_led_device *led)
 	if (!led->cfg_data)
 		return -ENOMEM;
 
-	ret = max77693_led_parse_dt(led, dev->of_node);
+	ret = max77693_led_parse_dt(led, dev->of_node, sub_nodes);
 	if (ret < 0)
 		return ret;
 
@@ -841,6 +879,12 @@ static const struct led_flash_ops flash_ops = {
 	.fault_get		= max77693_led_flash_fault_get,
 };
 
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+static const struct v4l2_flash_ops v4l2_flash_ops = {
+	.external_strobe_set = max77693_led_external_strobe_set,
+};
+#endif
+
 static void max77693_init_flash_settings(struct max77693_led_device *led,
 					 struct max77693_led_settings *s,
 					 int fled_id)
@@ -875,6 +919,47 @@ static void max77693_init_flash_settings(struct max77693_led_device *led,
 	setting->val = setting->max;
 }
 
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+static void max77693_init_v4l2_ctrl_config(struct max77693_led_settings *s,
+					struct max77693_led_config_data *p,
+					struct v4l2_flash_ctrl_config *config,
+					int fled_id)
+{
+	struct led_flash_setting *setting;
+	struct v4l2_ctrl_config *c;
+
+	c = &config->intensity;
+	setting = &s->torch_brightness;
+	c->min = setting->min;
+	c->max = setting->max;
+	c->step = setting->step;
+	c->def = setting->val;
+
+	c = &config->flash_intensity;
+	setting = &s->flash_brightness;
+	c->min = setting->min;
+	c->max = setting->max;
+	c->step = setting->step;
+	c->def = setting->val;
+
+	c = &config->flash_timeout;
+	setting = &s->flash_timeout;
+	c->min = setting->min;
+	c->max = setting->max;
+	c->step = setting->step;
+	c->def = setting->val;
+
+	/* Init flash faults config */
+	config->flash_faults =	V4L2_FLASH_FAULT_OVER_VOLTAGE |
+				V4L2_FLASH_FAULT_SHORT_CIRCUIT |
+				V4L2_FLASH_FAULT_OVER_CURRENT;
+
+	config->has_external_strobe = true;
+}
+#else
+#define max77693_init_v4l2_ctrl_config(s, p, config, fled_id)
+#endif
+
 static int max77693_set_available_sync_led(struct max77693_led_device *led,
 						int fled_id)
 {
@@ -893,7 +978,8 @@ static int max77693_set_available_sync_led(struct max77693_led_device *led,
 }
 
 static void max77693_init_fled_cdev(struct max77693_led_device *led,
-					int fled_id)
+				int fled_id,
+				struct v4l2_flash_ctrl_config *v4l2_flash_cfg)
 {
 	struct led_classdev_flash *fled_cdev;
 	struct led_classdev *led_cdev;
@@ -902,6 +988,9 @@ static void max77693_init_fled_cdev(struct max77693_led_device *led,
 
 	/* Initialize flash settings */
 	max77693_init_flash_settings(led, &settings, fled_id);
+	/* Initialize V4L2 Flash config basing on initialized settings */
+	max77693_init_v4l2_ctrl_config(&settings, led->cfg_data,
+					v4l2_flash_cfg, fled_id);
 
 	/* Initialize LED Flash class device */
 	fled_cdev = &sub_led->fled_cdev;
@@ -924,14 +1013,51 @@ static void max77693_init_fled_cdev(struct max77693_led_device *led,
 	sub_led->flash_timeout = fled_cdev->timeout.val;
 }
 
+static int max77693_register_led(struct max77693_sub_led *sub_led,
+				 struct v4l2_flash_ctrl_config *v4l2_flash_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;
+	int ret;
+
+	/* Register in the LED subsystem */
+	ret = led_classdev_flash_register(dev, fled_cdev);
+	if (ret < 0)
+		return ret;
+
+	of_node_get(sub_node);
+	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_flash_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:
+	of_node_put(sub_node);
+	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] = { NULL, NULL };
+	struct v4l2_flash_ctrl_config v4l2_flash_config[2];
 	int init_fled_cdev[2], i, ret;
 
+	memset(v4l2_flash_config, 0, sizeof(v4l2_flash_config));
+
 	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
 	if (!led)
 		return -ENOMEM;
@@ -941,7 +1067,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);
+	ret = max77693_led_get_configuration(led, sub_nodes);
 	if (ret < 0)
 		return ret;
 
@@ -957,7 +1083,7 @@ static int max77693_led_probe(struct platform_device *pdev)
 	/* Initialize LED Flash class device(s) */
 	for (i = FLED1; i <= FLED2; ++i)
 		if (init_fled_cdev[i])
-			max77693_init_fled_cdev(led, i);
+			max77693_init_fled_cdev(led, i, &v4l2_flash_config[i]);
 
 	/* Setup sub-leds available for flash strobe synchronization */
 	if (led->cfg_data->num_leds == 2) {
@@ -970,11 +1096,12 @@ static int max77693_led_probe(struct platform_device *pdev)
 
 	mutex_init(&led->lock);
 
-	/* Register LED Flash class device(s) */
+	/* Register LED Flash class and related V4L2 Flash device(s) */
 	for (i = FLED1; i <= FLED2; ++i) {
 		if (init_fled_cdev[i]) {
-			ret = led_classdev_flash_register(dev,
-							&sub_leds[i].fled_cdev);
+			ret = max77693_register_led(&sub_leds[i],
+						    &v4l2_flash_config[i],
+						    sub_nodes[i]);
 			if (ret < 0) {
 				/*
 				 * At this moment FLED1 might have been already
@@ -995,6 +1122,8 @@ 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);
+	of_node_put(sub_leds[FLED1].fled_cdev.led_cdev.dev->of_node);
 	led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
 err_register_led1:
 	mutex_destroy(&led->lock);
@@ -1008,11 +1137,15 @@ 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);
+		of_node_put(sub_leds[FLED1].fled_cdev.led_cdev.dev->of_node);
 		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);
+		of_node_put(sub_leds[FLED2].fled_cdev.led_cdev.dev->of_node);
 		led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);
 		cancel_work_sync(&sub_leds[FLED2].work_brightness_set);
 	}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH/RFC v10 19/19] leds: aat1290: add support for V4L2 Flash sub-device
  2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
                   ` (17 preceding siblings ...)
  2015-01-09 15:23 ` [PATCH/RFC v10 18/19] leds: max77693: add support for V4L2 Flash sub-device Jacek Anaszewski
@ 2015-01-09 15:23 ` Jacek Anaszewski
       [not found]   ` <1420816989-1808-20-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  18 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-09 15:23 UTC (permalink / raw)
  To: linux-leds, linux-media, linux-kernel
  Cc: devicetree, kyungmin.park, b.zolnierkie, pavel, cooloney,
	rpurdie, sakari.ailus, s.nawrocki, Jacek Anaszewski,
	Sakari Ailus

Add support for V4L2 Flash sub-device to the aat1290 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@linux.intel.com>
---
 drivers/leds/leds-aat1290.c |   62 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c
index 0a3c9b4..0974868 100644
--- a/drivers/leds/leds-aat1290.c
+++ b/drivers/leds/leds-aat1290.c
@@ -20,6 +20,7 @@
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <media/v4l2-flash.h>
 #include <linux/workqueue.h>
 
 #define AAT1290_MOVIE_MODE_CURRENT_ADDR	17
@@ -67,6 +68,7 @@ struct aat1290_led {
 	struct mutex lock;
 
 	struct led_classdev_flash fled_cdev;
+	struct v4l2_flash *v4l2_flash;
 
 	int flen_gpio;
 	int en_set_gpio;
@@ -280,11 +282,44 @@ static void aat1290_init_flash_settings(struct aat1290_led *led,
 	setting->val = setting->max;
 }
 
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+static void aat1290_init_v4l2_ctrl_config(struct aat1290_led_settings *s,
+					struct v4l2_flash_ctrl_config *config)
+{
+	struct led_flash_setting *setting;
+	struct v4l2_ctrl_config *c;
+
+	c = &config->intensity;
+	setting = &s->torch_brightness;
+	c->min = setting->min;
+	c->max = setting->max;
+	c->step = setting->step;
+	c->def = setting->val;
+
+	c = &config->flash_timeout;
+	setting = &s->flash_timeout;
+	c->min = setting->min;
+	c->max = setting->max;
+	c->step = setting->step;
+	c->def = setting->val;
+
+	config->has_external_strobe = false;
+}
+#else
+#define aat1290_init_v4l2_ctrl_config(s, config)
+#endif
+
 static const struct led_flash_ops flash_ops = {
 	.strobe_set = aat1290_led_flash_strobe_set,
 	.timeout_set = aat1290_led_flash_timeout_set,
 };
 
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+static const struct v4l2_flash_ops v4l2_flash_ops = {
+	.external_strobe_set = NULL,
+};
+#endif
+
 static int aat1290_led_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -292,6 +327,9 @@ static int aat1290_led_probe(struct platform_device *pdev)
 	struct aat1290_led *led;
 	struct led_classdev *led_cdev;
 	struct led_classdev_flash *fled_cdev;
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+	struct v4l2_flash_ctrl_config v4l2_flash_config;
+#endif
 	struct aat1290_led_settings settings;
 	int flen_gpio, enset_gpio, ret;
 
@@ -342,6 +380,9 @@ static int aat1290_led_probe(struct platform_device *pdev)
 
 	fled_cdev->timeout = settings.flash_timeout;
 
+	/* Init V4L2 Flash controls basing on initialized settings */
+	aat1290_init_v4l2_ctrl_config(&settings, &v4l2_flash_config);
+
 	/* Init led class */
 	led_cdev = &fled_cdev->led_cdev;
 	led_cdev->name = led->label;
@@ -361,13 +402,34 @@ static int aat1290_led_probe(struct platform_device *pdev)
 
 	mutex_init(&led->lock);
 
+	of_node_get(dev_node);
+	led_cdev->dev->of_node = dev_node;
+
+	/* Create V4L2 Flash subdev. */
+	led->v4l2_flash = v4l2_flash_init(fled_cdev,
+					  &v4l2_flash_ops,
+					  &v4l2_flash_config);
+	if (IS_ERR(led->v4l2_flash)) {
+		ret = PTR_ERR(led->v4l2_flash);
+		goto error_v4l2_flash_init;
+	}
+
 	return 0;
+
+error_v4l2_flash_init:
+	of_node_put(dev_node);
+	led_classdev_flash_unregister(fled_cdev);
+	mutex_destroy(&led->lock);
+
+	return ret;
 }
 
 static int aat1290_led_remove(struct platform_device *pdev)
 {
 	struct aat1290_led *led = platform_get_drvdata(pdev);
 
+	v4l2_flash_release(led->v4l2_flash);
+	of_node_put(led->fled_cdev.led_cdev.dev->of_node);
 	led_classdev_flash_unregister(&led->fled_cdev);
 	cancel_work_sync(&led->work_brightness_set);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 01/19] leds: Add LED Flash class extension to the LED subsystem
  2015-01-09 15:22 ` [PATCH/RFC v10 01/19] leds: Add LED Flash class extension to the LED subsystem Jacek Anaszewski
@ 2015-01-09 17:37   ` Pavel Machek
  2015-01-26 23:02     ` Bryan Wu
  0 siblings, 1 reply; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 17:37 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki

On Fri 2015-01-09 16:22:51, Jacek Anaszewski wrote:
> Some LED devices support two operation modes - torch and flash.
> This patch provides support for flash LED devices in the LED subsystem
> by introducing new sysfs attributes and kernel internal interface.
> The attributes being introduced are: flash_brightness, flash_strobe,
> flash_timeout, max_flash_timeout, max_flash_brightness, flash_fault,
> flash_sync_strobe and available_sync_leds. All the flash related
> features are placed in a separate module.
> 
> The modifications aim to be compatible with V4L2 framework requirements
> related to the flash devices management. The design assumes that V4L2
> sub-device can take of the LED class device control and communicate
> with it through the kernel internal interface. When V4L2 Flash sub-device
> file is opened, the LED class device sysfs interface is made
> unavailable.
> 
> 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>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 02/19] Documentation: leds: Add description of LED Flash class extension
  2015-01-09 15:22 ` [PATCH/RFC v10 02/19] Documentation: leds: Add description of LED Flash class extension Jacek Anaszewski
@ 2015-01-09 17:40   ` Pavel Machek
  2015-01-12  8:04     ` Jacek Anaszewski
  0 siblings, 1 reply; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 17:40 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki

Hi!

> The documentation being added contains overall description of the
> LED Flash Class and the related sysfs attributes.
> 
> 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>

> +In order to enable support for flash LEDs CONFIG_LEDS_CLASS_FLASH symbol
> +must be defined in the kernel config. A flash LED driver must register
> +in the LED subsystem with led_classdev_flash_register function to gain flash
> +related capabilities.
> +
> +There are flash LED devices which can control more than one LED and allow for
> +strobing the sub-leds synchronously. A LED will be strobed synchronously with
> +the one whose identifier is written to the flash_sync_strobe sysfs attribute.
> +The list of available sub-led identifiers can be read from the

sub-LED?

> +	- flash_fault - bitmask of flash faults that may have occurred
> +			possible flags are:
> +		* 0x01 - flash controller voltage to the flash LED has exceeded
> +			 the limit specific to the flash controller
> +		* 0x02 - the flash strobe was still on when the timeout set by
> +			 the user has expired; not all flash controllers may
> +			 set this in all such conditions
> +		* 0x04 - the flash controller has overheated
> +		* 0x08 - the short circuit protection of the flash controller
> +			 has been triggered
> +		* 0x10 - current in the LED power supply has exceeded the limit
> +			 specific to the flash controller
> +		* 0x20 - the flash controller has detected a short or open
> +			 circuit condition on the indicator LED
> +		* 0x40 - flash controller voltage to the flash LED has been
> +			 below the minimum limit specific to the flash
> +		* 0x80 - the input voltage of the flash controller is below
> +			 the limit under which strobing the flash at full
> +			 current will not be possible. The condition persists
> +			 until this flag is no longer set
> +		* 0x100 - the temperature of the LED has exceeded its allowed
> +			  upper limit

Did not everyone agree that text strings are preferable to bitmasks?

									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-09 15:22 ` [PATCH/RFC v10 03/19] DT: leds: Add led-sources property Jacek Anaszewski
@ 2015-01-09 17:42   ` Pavel Machek
       [not found]   ` <1420816989-1808-4-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  1 sibling, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 17:42 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On Fri 2015-01-09 16:22:53, Jacek Anaszewski wrote:
> Add a property for defining the device outputs the LED
> represented by the DT child node is connected to.
> 
> 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: Rob Herring <robh+dt@kernel.org>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: Kumar Gala <galak@codeaurora.org>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros
  2015-01-09 15:22 ` [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros Jacek Anaszewski
@ 2015-01-09 17:43   ` Pavel Machek
  2015-01-20 11:12   ` Lee Jones
  1 sibling, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 17:43 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Lee Jones, Chanwoo Choi

On Fri 2015-01-09 16:22:54, Jacek Anaszewski wrote:
> Add macros for max77693 led part related binding.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Lee Jones <lee.jones@linaro.org>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>

Acked-by: Pavel Machek <pavel@ucw.cz>
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693
  2015-01-09 15:22 ` [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693 Jacek Anaszewski
@ 2015-01-09 17:52   ` Pavel Machek
  2015-01-20 11:21   ` Lee Jones
  1 sibling, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 17:52 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Andrzej Hajda, Lee Jones, Chanwoo Choi, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala

On Fri 2015-01-09 16:22:59, Jacek Anaszewski wrote:
> This patch adds device tree binding documentation for
> the flash cell of the Maxim max77693 multifunctional device.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>

Acked-by: Pavel Machek <pavel@ucw.cz>

> diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
> index 01e9f30..ef184f0 100644
> --- a/Documentation/devicetree/bindings/mfd/max77693.txt
> +++ b/Documentation/devicetree/bindings/mfd/max77693.txt
> @@ -41,7 +41,52 @@ Optional properties:
>  	 To get more informations, please refer to documentaion.
>  	[*] refer Documentation/devicetree/bindings/pwm/pwm.txt
>  
> +- led : the LED submodule device node
> +
> +There are two led outputs available - fled1 and fled2. Each of them can

led->LED (around 4x).

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers
  2015-01-09 15:22 ` [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers Jacek Anaszewski
@ 2015-01-09 17:53   ` Pavel Machek
       [not found]   ` <1420816989-1808-6-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  1 sibling, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 17:53 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi, Lee Jones

On Fri 2015-01-09 16:22:55, Jacek Anaszewski wrote:
> Change flash cell identifiers from max77693-flash to max77693-led
> to avoid confusion with NOR/NAND Flash.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Cc: Lee Jones <lee.jones@linaro.org>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 06/19] mfd: max77693: modifications around max77693_led_platform_data
  2015-01-09 15:22 ` [PATCH/RFC v10 06/19] mfd: max77693: modifications around max77693_led_platform_data Jacek Anaszewski
@ 2015-01-09 17:56   ` Pavel Machek
       [not found]   ` <1420816989-1808-7-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  1 sibling, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 17:56 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi, Lee Jones

On Fri 2015-01-09 16:22:56, Jacek Anaszewski wrote:
> 1. Rename max77693_led_platform_data to max77693_led_config_data to
>    avoid making impression that the led driver expects a board file -
>    it relies on Device Tree data.
> 2. Remove fleds array, as the DT binding design has changed
> 3. Add "label" array for Device Tree strings with the name of a LED device
> 4. Make flash_timeout a two element array, for caching the sub-led
>    related flash timeout.
> 5. Remove trigger array as the related data will not be provided
>    in the DT binding
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Cc: Lee Jones <lee.jones@linaro.org>

Seems that max77693_led_platform_data is unused at the moment, so it
should not break bisect.

Acked-by: Pavel Machek <pavel@ucw.cz>

> index f0b6585..c1ccb13 100644
> --- a/include/linux/mfd/max77693.h
> +++ b/include/linux/mfd/max77693.h
> @@ -87,17 +87,16 @@ enum max77693_led_boost_mode {
>  	MAX77693_LED_BOOST_FIXED,
>  };
>  
> -struct max77693_led_platform_data {
> -	u32 fleds[2];
> +struct max77693_led_config_data {
> +	const char *label[2];
>  	u32 iout_torch[2];
>  	u32 iout_flash[2];

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros
  2015-01-09 15:22 ` [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros Jacek Anaszewski
@ 2015-01-09 17:59   ` Pavel Machek
  2015-01-20 11:17   ` Lee Jones
  1 sibling, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 17:59 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi, Lee Jones

On Fri 2015-01-09 16:22:57, Jacek Anaszewski wrote:
> Modify FLASH_EN_SHIFT and TORCH_EN_SHIFT macros to work properly
> when passed enum max77693_fled values (0 for FLED1 and 1 for FLED2)
> from leds-max77693 driver.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Cc: Lee Jones <lee.jones@linaro.org>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-09 15:22 ` [PATCH/RFC v10 03/19] DT: leds: Add led-sources property Jacek Anaszewski
@ 2015-01-09 18:33       ` Rob Herring
       [not found]   ` <1420816989-1808-4-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  1 sibling, 0 replies; 107+ messages in thread
From: Rob Herring @ 2015-01-09 18:33 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus-X3B1VOXEql0, Sylwester Nawrocki,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
<j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
> Add a property for defining the device outputs the LED
> represented by the DT child node is connected to.
>
> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Bryan Wu <cooloney-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Cc: Richard Purdie <rpurdie-Fm38FmjxZ/leoWH0uzbU5w@public.gmane.org>
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Pawel Moll <pawel.moll-5wv7dgnIgG8@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> Cc: Ian Campbell <ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org>
> Cc: Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/leds/common.txt |    5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt
> index a2c3f7a..29295bf 100644
> --- a/Documentation/devicetree/bindings/leds/common.txt
> +++ b/Documentation/devicetree/bindings/leds/common.txt
> @@ -1,6 +1,10 @@
>  Common leds properties.
>
>  Optional properties for child nodes:
> +- led-sources : Array of bits signifying the LED current regulator outputs the
> +               LED represented by the child node is connected to (1 - the LED
> +               is connected to the output, 0 - the LED isn't connected to the
> +               output).

Sorry, I just don't understand this.

Rob

>  - label : The label for this LED.  If omitted, the label is
>    taken from the node name (excluding the unit address).
>
> @@ -33,6 +37,7 @@ system-status {
>
>  camera-flash {
>         label = "Flash";
> +       led-sources = <1 0>;
>         max-microamp = <50000>;
>         flash-max-microamp = <320000>;
>         flash-timeout-us = <500000>;
> --
> 1.7.9.5
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
@ 2015-01-09 18:33       ` Rob Herring
  0 siblings, 0 replies; 107+ messages in thread
From: Rob Herring @ 2015-01-09 18:33 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
<j.anaszewski@samsung.com> wrote:
> Add a property for defining the device outputs the LED
> represented by the DT child node is connected to.
>
> 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: Rob Herring <robh+dt@kernel.org>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: Kumar Gala <galak@codeaurora.org>
> ---
>  Documentation/devicetree/bindings/leds/common.txt |    5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt
> index a2c3f7a..29295bf 100644
> --- a/Documentation/devicetree/bindings/leds/common.txt
> +++ b/Documentation/devicetree/bindings/leds/common.txt
> @@ -1,6 +1,10 @@
>  Common leds properties.
>
>  Optional properties for child nodes:
> +- led-sources : Array of bits signifying the LED current regulator outputs the
> +               LED represented by the child node is connected to (1 - the LED
> +               is connected to the output, 0 - the LED isn't connected to the
> +               output).

Sorry, I just don't understand this.

Rob

>  - label : The label for this LED.  If omitted, the label is
>    taken from the node name (excluding the unit address).
>
> @@ -33,6 +37,7 @@ system-status {
>
>  camera-flash {
>         label = "Flash";
> +       led-sources = <1 0>;
>         max-microamp = <50000>;
>         flash-max-microamp = <320000>;
>         flash-timeout-us = <500000>;
> --
> 1.7.9.5
>

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell
  2015-01-09 15:22 ` [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell Jacek Anaszewski
@ 2015-01-09 18:46       ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 18:46 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Andrzej Hajda, Lee Jones, Chanwoo Choi

On Fri 2015-01-09 16:22:58, Jacek Anaszewski wrote:
> This patch adds led-flash support to Maxim max77693 chipset.
> A device can be exposed to user space through LED subsystem
> sysfs interface. Device supports up to two leds which can
> work in flash and torch mode. The leds can be triggered
> externally or by software.
> 

> +struct max77693_sub_led {
> +	/* related FLED output identifier */

->flash LED, about 4x.

> +/* split composite current @i into two @iout according to @imax weights */
> +static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
> +{
> +	u64 t = i;
> +
> +	t *= imax[1];
> +	do_div(t, imax[0] + imax[1]);
> +
> +	iout[1] = (u32)t / FLASH_IOUT_STEP * FLASH_IOUT_STEP;
> +	iout[0] = i - iout[1];
> +}

Is 64-bit arithmetics neccessary here? Could we do the FLASH_IOUT_STEP
divisons before t *=, so that 64-bit division is not neccessary?

> +static int max77693_led_flash_strobe_get(
> +				struct led_classdev_flash *fled_cdev,
> +				bool *state)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +	int ret;
> +
> +	if (!state)
> +		return -EINVAL;
> +
> +	mutex_lock(&led->lock);
> +
> +	ret = max77693_strobe_status_get(led, state);
> +
> +	*state = !!(*state && (led->strobing_sub_led_id == sub_led->fled_id));
> +
> +
> +	mutex_unlock(&led->lock);
> +
> +	return ret;
> +}

Maybe remove some empty lines?

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell
@ 2015-01-09 18:46       ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 18:46 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Andrzej Hajda, Lee Jones, Chanwoo Choi

On Fri 2015-01-09 16:22:58, Jacek Anaszewski wrote:
> This patch adds led-flash support to Maxim max77693 chipset.
> A device can be exposed to user space through LED subsystem
> sysfs interface. Device supports up to two leds which can
> work in flash and torch mode. The leds can be triggered
> externally or by software.
> 

> +struct max77693_sub_led {
> +	/* related FLED output identifier */

->flash LED, about 4x.

> +/* split composite current @i into two @iout according to @imax weights */
> +static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
> +{
> +	u64 t = i;
> +
> +	t *= imax[1];
> +	do_div(t, imax[0] + imax[1]);
> +
> +	iout[1] = (u32)t / FLASH_IOUT_STEP * FLASH_IOUT_STEP;
> +	iout[0] = i - iout[1];
> +}

Is 64-bit arithmetics neccessary here? Could we do the FLASH_IOUT_STEP
divisons before t *=, so that 64-bit division is not neccessary?

> +static int max77693_led_flash_strobe_get(
> +				struct led_classdev_flash *fled_cdev,
> +				bool *state)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +	int ret;
> +
> +	if (!state)
> +		return -EINVAL;
> +
> +	mutex_lock(&led->lock);
> +
> +	ret = max77693_strobe_status_get(led, state);
> +
> +	*state = !!(*state && (led->strobing_sub_led_id == sub_led->fled_id));
> +
> +
> +	mutex_unlock(&led->lock);
> +
> +	return ret;
> +}

Maybe remove some empty lines?

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 10/19] leds: Add driver for AAT1290 current regulator
  2015-01-09 15:23     ` Jacek Anaszewski
@ 2015-01-09 18:57         ` Pavel Machek
  -1 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 18:57 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ

On Fri 2015-01-09 16:23:00, Jacek Anaszewski wrote:
> This patch adds a driver for the 1.5A Step-Up Current Regulator
> for Flash LEDs. The device is programmed through a Skyworks proprietary
> AS2Cwire serial digital interface.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Bryan Wu <cooloney-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Cc: Richard Purdie <rpurdie-Fm38FmjxZ/leoWH0uzbU5w@public.gmane.org>

Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 10/19] leds: Add driver for AAT1290 current regulator
@ 2015-01-09 18:57         ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 18:57 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki

On Fri 2015-01-09 16:23:00, Jacek Anaszewski wrote:
> This patch adds a driver for the 1.5A Step-Up Current Regulator
> for Flash LEDs. The device is programmed through a Skyworks proprietary
> AS2Cwire serial digital interface.
> 
> 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>

Acked-by: Pavel Machek <pavel@ucw.cz>
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 11/19] of: Add Skyworks Solutions, Inc. vendor prefix
  2015-01-09 15:23 ` [PATCH/RFC v10 11/19] of: Add Skyworks Solutions, Inc. vendor prefix Jacek Anaszewski
@ 2015-01-09 18:57       ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 18:57 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On Fri 2015-01-09 16:23:01, Jacek Anaszewski wrote:
> Use "skyworks" as the vendor prefix for the Skyworks Solutions, Inc.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Pawel Moll <pawel.moll-5wv7dgnIgG8@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> Cc: Ian Campbell <ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org>
> Cc: Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 11/19] of: Add Skyworks Solutions, Inc. vendor prefix
@ 2015-01-09 18:57       ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 18:57 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On Fri 2015-01-09 16:23:01, Jacek Anaszewski wrote:
> Use "skyworks" as the vendor prefix for the Skyworks Solutions, Inc.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: Kumar Gala <galak@codeaurora.org>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 12/19] DT: Add documentation for the Skyworks AAT1290
  2015-01-09 15:23 ` [PATCH/RFC v10 12/19] DT: Add documentation for the Skyworks AAT1290 Jacek Anaszewski
@ 2015-01-09 18:58   ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 18:58 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On Fri 2015-01-09 16:23:02, Jacek Anaszewski wrote:
> This patch adds device tree binding documentation for
> 1.5A Step-Up Current Regulator for Flash LEDs.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 13/19] exynos4-is: Add support for v4l2-flash subdevs
  2015-01-09 15:23 ` [PATCH/RFC v10 13/19] exynos4-is: Add support for v4l2-flash subdevs Jacek Anaszewski
@ 2015-01-09 19:06   ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 19:06 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki

On Fri 2015-01-09 16:23:03, Jacek Anaszewski wrote:
> This patch adds suppport for external v4l2-flash devices.
> The support includes parsing camera-flash DT property
> and asynchronous subdevice registration.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Sylwester Nawrocki <s.nawrocki@samsung.com>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 14/19] v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control
  2015-01-09 15:23 ` [PATCH/RFC v10 14/19] v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control Jacek Anaszewski
@ 2015-01-09 19:06       ` Pavel Machek
  2015-02-05 16:36   ` Sakari Ailus
  1 sibling, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 19:06 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Hans Verkuil

On Fri 2015-01-09 16:23:04, Jacek Anaszewski wrote:
> Add V4L2_CID_FLASH_SYNC_STROBE control for determining
> whether a flash device strobe has to be synchronized
> with other flash leds controller by the same device.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Sakari Ailus <sakari.ailus-X3B1VOXEql0@public.gmane.org>
> Cc: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>

Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 14/19] v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control
@ 2015-01-09 19:06       ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 19:06 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Hans Verkuil

On Fri 2015-01-09 16:23:04, Jacek Anaszewski wrote:
> Add V4L2_CID_FLASH_SYNC_STROBE control for determining
> whether a flash device strobe has to be synchronized
> with other flash leds controller by the same device.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Sakari Ailus <sakari.ailus@iki.fi>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices
  2015-01-09 15:23 ` [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices Jacek Anaszewski
@ 2015-01-09 20:54   ` Pavel Machek
  2015-01-12  9:46       ` Jacek Anaszewski
  2015-02-05 17:59   ` Sakari Ailus
  1 sibling, 1 reply; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 20:54 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Hans Verkuil

On Fri 2015-01-09 16:23:05, Jacek Anaszewski wrote:
> This patch adds helper functions for registering/unregistering
> LED Flash class devices as V4L2 sub-devices. The functions should
> be called from the LED subsystem device driver. In case the
> support for V4L2 Flash sub-devices is disabled in the kernel
> config the functions' empty versions will be used.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Sakari Ailus <sakari.ailus@iki.fi>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Pavel Machek <pavel@ucw.cz>

> +	/*
> +	 * Indicator leds, unlike torch leds, are turned on/off basing
> on

leds -> LEDs.

> +	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
> +	 * Therefore it must be possible to set it to 0 level which in
> +	 * the LED subsystem reflects LED_OFF state.
> +	 */
> +	if (cdata_id != INDICATOR_INTENSITY)
> +		++__intensity;

And normally we'd do i++ instead of ++i, and avoid __ for local
variables...?

> +/**
> + * struct v4l2_flash_ctrl_config - V4L2 Flash controls initialization data
> + * @intensity:			constraints for the led in a non-flash mode
> + * @flash_intensity:		V4L2_CID_FLASH_INTENSITY settings constraints
> + * @flash_timeout:		V4L2_CID_FLASH_TIMEOUT constraints
> + * @flash_faults:		possible flash faults
> + * @has_external_strobe:	external strobe capability
> + * @indicator_led:		signifies that a led is of indicator type
> + */
> +struct v4l2_flash_ctrl_config {
> +	struct v4l2_ctrl_config intensity;
> +	struct v4l2_ctrl_config flash_intensity;
> +	struct v4l2_ctrl_config flash_timeout;
> +	u32 flash_faults;
> +	bool has_external_strobe:1;
> +	bool indicator_led:1;
> +};

I don't think you are supposed to do boolean bit arrays.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 16/19] Documentation: leds: Add description of v4l2-flash sub-device
  2015-01-09 15:23 ` [PATCH/RFC v10 16/19] Documentation: leds: Add description of v4l2-flash sub-device Jacek Anaszewski
@ 2015-01-09 20:57   ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 20:57 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki

On Fri 2015-01-09 16:23:06, Jacek Anaszewski wrote:
> This patch extends LED Flash class documention by
> the description of interactions with v4l2-flash sub-device.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Cc: Bryan Wu <cooloney@gmail.com>
> Cc: Richard Purdie <rpurdie@rpsys.net>

Acked-by: Pavel Machek <pavel@ucw.cz>


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 17/19] DT: Add documentation for exynos4-is 'flashes' property
  2015-01-09 15:23 ` [PATCH/RFC v10 17/19] DT: Add documentation for exynos4-is 'flashes' property Jacek Anaszewski
@ 2015-01-09 20:57   ` Pavel Machek
  2015-01-21 16:32   ` Sylwester Nawrocki
  1 sibling, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 20:57 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On Fri 2015-01-09 16:23:07, Jacek Anaszewski wrote:
> This patch adds a description of 'flashes' property
> to the samsung-fimc.txt.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Sylwester Nawrocki <s.nawrocki@samsung.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: Kumar Gala <galak@codeaurora.org>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 18/19] leds: max77693: add support for V4L2 Flash sub-device
  2015-01-09 15:23 ` [PATCH/RFC v10 18/19] leds: max77693: add support for V4L2 Flash sub-device Jacek Anaszewski
@ 2015-01-09 20:59   ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 20:59 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Sakari Ailus

On Fri 2015-01-09 16:23:08, Jacek Anaszewski wrote:
> 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>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 19/19] leds: aat1290: add support for V4L2 Flash sub-device
  2015-01-09 15:23 ` [PATCH/RFC v10 19/19] leds: aat1290: " Jacek Anaszewski
@ 2015-01-09 20:59       ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 20:59 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Sakari Ailus

On Fri 2015-01-09 16:23:09, Jacek Anaszewski wrote:
> Add support for V4L2 Flash sub-device to the aat1290 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-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Bryan Wu <cooloney-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Cc: Richard Purdie <rpurdie-Fm38FmjxZ/leoWH0uzbU5w@public.gmane.org>
> Cc: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 19/19] leds: aat1290: add support for V4L2 Flash sub-device
@ 2015-01-09 20:59       ` Pavel Machek
  0 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-09 20:59 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Sakari Ailus

On Fri 2015-01-09 16:23:09, Jacek Anaszewski wrote:
> Add support for V4L2 Flash sub-device to the aat1290 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@linux.intel.com>

Acked-by: Pavel Machek <pavel@ucw.cz>

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 02/19] Documentation: leds: Add description of LED Flash class extension
  2015-01-09 17:40   ` Pavel Machek
@ 2015-01-12  8:04     ` Jacek Anaszewski
  2015-01-26 23:03       ` Bryan Wu
  0 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-12  8:04 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki

Hi Pavel,

Thanks for the review.

On 01/09/2015 06:40 PM, Pavel Machek wrote:
> Hi!
>
>> The documentation being added contains overall description of the
>> LED Flash Class and the related sysfs attributes.
>>
>> 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>
>
>> +In order to enable support for flash LEDs CONFIG_LEDS_CLASS_FLASH symbol
>> +must be defined in the kernel config. A flash LED driver must register
>> +in the LED subsystem with led_classdev_flash_register function to gain flash
>> +related capabilities.
>> +
>> +There are flash LED devices which can control more than one LED and allow for
>> +strobing the sub-leds synchronously. A LED will be strobed synchronously with
>> +the one whose identifier is written to the flash_sync_strobe sysfs attribute.
>> +The list of available sub-led identifiers can be read from the
>
> sub-LED?

Indeed, this naming will be more consistent.

>> +	- flash_fault - bitmask of flash faults that may have occurred
>> +			possible flags are:
>> +		* 0x01 - flash controller voltage to the flash LED has exceeded
>> +			 the limit specific to the flash controller
>> +		* 0x02 - the flash strobe was still on when the timeout set by
>> +			 the user has expired; not all flash controllers may
>> +			 set this in all such conditions
>> +		* 0x04 - the flash controller has overheated
>> +		* 0x08 - the short circuit protection of the flash controller
>> +			 has been triggered
>> +		* 0x10 - current in the LED power supply has exceeded the limit
>> +			 specific to the flash controller
>> +		* 0x20 - the flash controller has detected a short or open
>> +			 circuit condition on the indicator LED
>> +		* 0x40 - flash controller voltage to the flash LED has been
>> +			 below the minimum limit specific to the flash
>> +		* 0x80 - the input voltage of the flash controller is below
>> +			 the limit under which strobing the flash at full
>> +			 current will not be possible. The condition persists
>> +			 until this flag is no longer set
>> +		* 0x100 - the temperature of the LED has exceeded its allowed
>> +			  upper limit
>
> Did not everyone agree that text strings are preferable to bitmasks?
>
> 									Pavel
>

I just forgot to update the flash_fault documentation. Will fix in the
next version.

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-09 18:33       ` Rob Herring
  (?)
@ 2015-01-12  8:32       ` Jacek Anaszewski
  2015-01-12 13:52         ` Rob Herring
  -1 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-12  8:32 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On 01/09/2015 07:33 PM, Rob Herring wrote:
> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
> <j.anaszewski@samsung.com> wrote:
>> Add a property for defining the device outputs the LED
>> represented by the DT child node is connected to.
>>
>> 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: Rob Herring <robh+dt@kernel.org>
>> Cc: Pawel Moll <pawel.moll@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
>> Cc: Kumar Gala <galak@codeaurora.org>
>> ---
>>   Documentation/devicetree/bindings/leds/common.txt |    5 +++++
>>   1 file changed, 5 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt
>> index a2c3f7a..29295bf 100644
>> --- a/Documentation/devicetree/bindings/leds/common.txt
>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>> @@ -1,6 +1,10 @@
>>   Common leds properties.
>>
>>   Optional properties for child nodes:
>> +- led-sources : Array of bits signifying the LED current regulator outputs the
>> +               LED represented by the child node is connected to (1 - the LED
>> +               is connected to the output, 0 - the LED isn't connected to the
>> +               output).
>
> Sorry, I just don't understand this.

In some Flash LED devices one LED can be connected to one or more
electric current outputs, which allows for multiplying the maximum
current allowed for the LED. Each sub-LED is represented by a child
node in the DT binding of the Flash LED device and it needs to declare
which outputs it is connected to. In the example below the led-sources
property is a two element array, which means that the flash LED device
has two current outputs, and the bits signify if the LED is connected
to the output.

Do your doubts stem from the ambiguity of the word "current" or the
form of the description itself is unclear? Probably there should be
explicit explanation added that the size of the array depends on the
number of current outputs of the flash LED device.

>>   - label : The label for this LED.  If omitted, the label is
>>     taken from the node name (excluding the unit address).
>>
>> @@ -33,6 +37,7 @@ system-status {
>>
>>   camera-flash {
>>          label = "Flash";
>> +       led-sources = <1 0>;
>>          max-microamp = <50000>;
>>          flash-max-microamp = <320000>;
>>          flash-timeout-us = <500000>;
>> --
>> 1.7.9.5
>>
>

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell
  2015-01-09 18:46       ` Pavel Machek
  (?)
@ 2015-01-12  8:52       ` Jacek Anaszewski
  2015-01-12 13:25         ` Pavel Machek
  -1 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-12  8:52 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Andrzej Hajda, Lee Jones, Chanwoo Choi

Hi Pavel,

Thanks for the review.

On 01/09/2015 07:46 PM, Pavel Machek wrote:
> On Fri 2015-01-09 16:22:58, Jacek Anaszewski wrote:
>> This patch adds led-flash support to Maxim max77693 chipset.
>> A device can be exposed to user space through LED subsystem
>> sysfs interface. Device supports up to two leds which can
>> work in flash and torch mode. The leds can be triggered
>> externally or by software.
>>
>
>> +struct max77693_sub_led {
>> +	/* related FLED output identifier */
>
> ->flash LED, about 4x.
>
>> +/* split composite current @i into two @iout according to @imax weights */
>> +static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
>> +{
>> +	u64 t = i;
>> +
>> +	t *= imax[1];
>> +	do_div(t, imax[0] + imax[1]);
>> +
>> +	iout[1] = (u32)t / FLASH_IOUT_STEP * FLASH_IOUT_STEP;
>> +	iout[0] = i - iout[1];
>> +}
>
> Is 64-bit arithmetics neccessary here? Could we do the FLASH_IOUT_STEP
> divisons before t *=, so that 64-bit division is not neccessary?

It is required. All these operations allow for splitting the composite
current into both outputs according to weights given in the imax array.

>> +static int max77693_led_flash_strobe_get(
>> +				struct led_classdev_flash *fled_cdev,
>> +				bool *state)
>> +{
>> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
>> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
>> +	int ret;
>> +
>> +	if (!state)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&led->lock);
>> +
>> +	ret = max77693_strobe_status_get(led, state);
>> +
>> +	*state = !!(*state && (led->strobing_sub_led_id == sub_led->fled_id));
>> +
>> +
>> +	mutex_unlock(&led->lock);
>> +
>> +	return ret;
>> +}
>
> Maybe remove some empty lines?
>

Of course.

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices
  2015-01-09 20:54   ` Pavel Machek
@ 2015-01-12  9:46       ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-12  9:46 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Hans Verkuil

Hi Pavel,

Thanks for the review.

On 01/09/2015 09:54 PM, Pavel Machek wrote:
> On Fri 2015-01-09 16:23:05, Jacek Anaszewski wrote:
>> This patch adds helper functions for registering/unregistering
>> LED Flash class devices as V4L2 sub-devices. The functions should
>> be called from the LED subsystem device driver. In case the
>> support for V4L2 Flash sub-devices is disabled in the kernel
>> config the functions' empty versions will be used.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Cc: Sakari Ailus <sakari.ailus-X3B1VOXEql0@public.gmane.org>
>> Cc: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
>
> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
>
>> +	/*
>> +	 * Indicator leds, unlike torch leds, are turned on/off basing
>> on
>
> leds -> LEDs.

Sure.

>> +	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
>> +	 * Therefore it must be possible to set it to 0 level which in
>> +	 * the LED subsystem reflects LED_OFF state.
>> +	 */
>> +	if (cdata_id != INDICATOR_INTENSITY)
>> +		++__intensity;
>
> And normally we'd do i++ instead of ++i, and avoid __ for local
> variables...?

Pre-incrementation operator is favourable over the post-incrementation
one if we don't want to have an access to the value of a variable before
incrementation, which is the case here.
Maybe gcc detects the cases when the value of a variable is not assigned
and doesn't copy it before incrementing, however I haven't found any
reference. I see that often in the for loops the i++ version
is used, but I am not sure if this is done because developers are
aware that gcc will optimize it anyway or it is just an omission.

And regarding __ for local variable - I haven't found any restriction
about it in the Documentation/CodingStyle. Nevertheless I can rename
it to tmp or something.

>> +/**
>> + * struct v4l2_flash_ctrl_config - V4L2 Flash controls initialization data
>> + * @intensity:			constraints for the led in a non-flash mode
>> + * @flash_intensity:		V4L2_CID_FLASH_INTENSITY settings constraints
>> + * @flash_timeout:		V4L2_CID_FLASH_TIMEOUT constraints
>> + * @flash_faults:		possible flash faults
>> + * @has_external_strobe:	external strobe capability
>> + * @indicator_led:		signifies that a led is of indicator type
>> + */
>> +struct v4l2_flash_ctrl_config {
>> +	struct v4l2_ctrl_config intensity;
>> +	struct v4l2_ctrl_config flash_intensity;
>> +	struct v4l2_ctrl_config flash_timeout;
>> +	u32 flash_faults;
>> +	bool has_external_strobe:1;
>> +	bool indicator_led:1;
>> +};
>
> I don't think you are supposed to do boolean bit arrays.

These bit fields allow to reduce memory usage. If they were not bit
fields, the address of the next variable would be aligned to the
multiply of the CPU word size.
Please look e.g. at struct dev_pm_info in the file include/linux/pm.h.
It also contains boolean bit fields.

-- 
Best Regards,
Jacek Anaszewski
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices
@ 2015-01-12  9:46       ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-12  9:46 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Hans Verkuil

Hi Pavel,

Thanks for the review.

On 01/09/2015 09:54 PM, Pavel Machek wrote:
> On Fri 2015-01-09 16:23:05, Jacek Anaszewski wrote:
>> This patch adds helper functions for registering/unregistering
>> LED Flash class devices as V4L2 sub-devices. The functions should
>> be called from the LED subsystem device driver. In case the
>> support for V4L2 Flash sub-devices is disabled in the kernel
>> config the functions' empty versions will be used.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> Cc: Sakari Ailus <sakari.ailus@iki.fi>
>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
>
> Acked-by: Pavel Machek <pavel@ucw.cz>
>
>> +	/*
>> +	 * Indicator leds, unlike torch leds, are turned on/off basing
>> on
>
> leds -> LEDs.

Sure.

>> +	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
>> +	 * Therefore it must be possible to set it to 0 level which in
>> +	 * the LED subsystem reflects LED_OFF state.
>> +	 */
>> +	if (cdata_id != INDICATOR_INTENSITY)
>> +		++__intensity;
>
> And normally we'd do i++ instead of ++i, and avoid __ for local
> variables...?

Pre-incrementation operator is favourable over the post-incrementation
one if we don't want to have an access to the value of a variable before
incrementation, which is the case here.
Maybe gcc detects the cases when the value of a variable is not assigned
and doesn't copy it before incrementing, however I haven't found any
reference. I see that often in the for loops the i++ version
is used, but I am not sure if this is done because developers are
aware that gcc will optimize it anyway or it is just an omission.

And regarding __ for local variable - I haven't found any restriction
about it in the Documentation/CodingStyle. Nevertheless I can rename
it to tmp or something.

>> +/**
>> + * struct v4l2_flash_ctrl_config - V4L2 Flash controls initialization data
>> + * @intensity:			constraints for the led in a non-flash mode
>> + * @flash_intensity:		V4L2_CID_FLASH_INTENSITY settings constraints
>> + * @flash_timeout:		V4L2_CID_FLASH_TIMEOUT constraints
>> + * @flash_faults:		possible flash faults
>> + * @has_external_strobe:	external strobe capability
>> + * @indicator_led:		signifies that a led is of indicator type
>> + */
>> +struct v4l2_flash_ctrl_config {
>> +	struct v4l2_ctrl_config intensity;
>> +	struct v4l2_ctrl_config flash_intensity;
>> +	struct v4l2_ctrl_config flash_timeout;
>> +	u32 flash_faults;
>> +	bool has_external_strobe:1;
>> +	bool indicator_led:1;
>> +};
>
> I don't think you are supposed to do boolean bit arrays.

These bit fields allow to reduce memory usage. If they were not bit
fields, the address of the next variable would be aligned to the
multiply of the CPU word size.
Please look e.g. at struct dev_pm_info in the file include/linux/pm.h.
It also contains boolean bit fields.

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell
  2015-01-12  8:52       ` Jacek Anaszewski
@ 2015-01-12 13:25         ` Pavel Machek
  2015-01-12 13:46           ` Jacek Anaszewski
  0 siblings, 1 reply; 107+ messages in thread
From: Pavel Machek @ 2015-01-12 13:25 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Andrzej Hajda, Lee Jones, Chanwoo Choi

Hi!

> >>+struct max77693_sub_led {
> >>+	/* related FLED output identifier */
> >
> >->flash LED, about 4x.
> >
> >>+/* split composite current @i into two @iout according to @imax weights */
> >>+static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
> >>+{
> >>+	u64 t = i;
> >>+
> >>+	t *= imax[1];
> >>+	do_div(t, imax[0] + imax[1]);
> >>+
> >>+	iout[1] = (u32)t / FLASH_IOUT_STEP * FLASH_IOUT_STEP;
> >>+	iout[0] = i - iout[1];
> >>+}
> >
> >Is 64-bit arithmetics neccessary here? Could we do the FLASH_IOUT_STEP
> >divisons before t *=, so that 64-bit division is not neccessary?
> 
> It is required. All these operations allow for splitting the composite
> current into both outputs according to weights given in the imax
>array.

I know.

What about this?

static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
{
	u32 t = i;

	t *= imax[1] / FLASH_IOUT_STEP;
	t = t / (imax[0] + imax[1]);
	t /= FLASH_IOUT_STEP

	iout[1] = (u32)t;
	iout[0] = i - iout[1];
}

Does it lack precision?

Thanks,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices
  2015-01-12  9:46       ` Jacek Anaszewski
  (?)
@ 2015-01-12 13:27       ` Pavel Machek
  -1 siblings, 0 replies; 107+ messages in thread
From: Pavel Machek @ 2015-01-12 13:27 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Hans Verkuil

Hi!

> >>+	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
> >>+	 * Therefore it must be possible to set it to 0 level which in
> >>+	 * the LED subsystem reflects LED_OFF state.
> >>+	 */
> >>+	if (cdata_id != INDICATOR_INTENSITY)
> >>+		++__intensity;
> >
> >And normally we'd do i++ instead of ++i, and avoid __ for local
> >variables...?
> 
> Pre-incrementation operator is favourable over the post-incrementation
> one if we don't want to have an access to the value of a variable before
> incrementation, which is the case here.

That may be some old C++ convention, but I'm pretty sure gcc does not
care.

> Maybe gcc detects the cases when the value of a variable is not assigned
> and doesn't copy it before incrementing, however I haven't found any
> reference. I see that often in the for loops the i++ version
> is used, but I am not sure if this is done because developers are
> aware that gcc will optimize it anyway or it is just an omission.

The code is equivalent, and normally the n++ version is used. gcc will
get it right.

> >>+struct v4l2_flash_ctrl_config {
> >>+	struct v4l2_ctrl_config intensity;
> >>+	struct v4l2_ctrl_config flash_intensity;
> >>+	struct v4l2_ctrl_config flash_timeout;
> >>+	u32 flash_faults;
> >>+	bool has_external_strobe:1;
> >>+	bool indicator_led:1;
> >>+};
> >
> >I don't think you are supposed to do boolean bit arrays.
> 
> These bit fields allow to reduce memory usage. If they were not bit
> fields, the address of the next variable would be aligned to the
> multiply of the CPU word size.
> Please look e.g. at struct dev_pm_info in the file include/linux/pm.h.
> It also contains boolean bit fields.

Looks like you are right. I guess I confused bool foo:1 with int
foo:1.

Thanks,
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell
  2015-01-12 13:25         ` Pavel Machek
@ 2015-01-12 13:46           ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-12 13:46 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Andrzej Hajda, Lee Jones, Chanwoo Choi

On 01/12/2015 02:25 PM, Pavel Machek wrote:
> Hi!
>
>>>> +struct max77693_sub_led {
>>>> +	/* related FLED output identifier */
>>>
>>> ->flash LED, about 4x.
>>>
>>>> +/* split composite current @i into two @iout according to @imax weights */
>>>> +static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
>>>> +{
>>>> +	u64 t = i;
>>>> +
>>>> +	t *= imax[1];
>>>> +	do_div(t, imax[0] + imax[1]);
>>>> +
>>>> +	iout[1] = (u32)t / FLASH_IOUT_STEP * FLASH_IOUT_STEP;
>>>> +	iout[0] = i - iout[1];
>>>> +}
>>>
>>> Is 64-bit arithmetics neccessary here? Could we do the FLASH_IOUT_STEP
>>> divisons before t *=, so that 64-bit division is not neccessary?
>>
>> It is required. All these operations allow for splitting the composite
>> current into both outputs according to weights given in the imax
>> array.
>
> I know.
>
> What about this?
>
> static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
> {
> 	u32 t = i;
>
> 	t *= imax[1] / FLASH_IOUT_STEP;

Let's consider following case:

t = 1000000
imax[1] = 1000000

multiplication of the above will give 10^12 - much more than
it is possible to encode on 32 bits.

> 	t = t / (imax[0] + imax[1]);
> 	t /= FLASH_IOUT_STEP
>
> 	iout[1] = (u32)t;
> 	iout[0] = i - iout[1];
> }
>
> Does it lack precision?
>
> Thanks,
> 									Pavel
>


-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-12  8:32       ` Jacek Anaszewski
@ 2015-01-12 13:52         ` Rob Herring
  2015-01-12 16:10           ` Jacek Anaszewski
  0 siblings, 1 reply; 107+ messages in thread
From: Rob Herring @ 2015-01-12 13:52 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
<j.anaszewski@samsung.com> wrote:
> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>
>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>> <j.anaszewski@samsung.com> wrote:
>>>
>>> Add a property for defining the device outputs the LED
>>> represented by the DT child node is connected to.
>>>
>>> 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: Rob Herring <robh+dt@kernel.org>
>>> Cc: Pawel Moll <pawel.moll@arm.com>
>>> Cc: Mark Rutland <mark.rutland@arm.com>
>>> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
>>> Cc: Kumar Gala <galak@codeaurora.org>
>>> ---
>>>   Documentation/devicetree/bindings/leds/common.txt |    5 +++++
>>>   1 file changed, 5 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/leds/common.txt
>>> b/Documentation/devicetree/bindings/leds/common.txt
>>> index a2c3f7a..29295bf 100644
>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>> @@ -1,6 +1,10 @@
>>>   Common leds properties.
>>>
>>>   Optional properties for child nodes:
>>> +- led-sources : Array of bits signifying the LED current regulator
>>> outputs the
>>> +               LED represented by the child node is connected to (1 -
>>> the LED
>>> +               is connected to the output, 0 - the LED isn't connected
>>> to the
>>> +               output).
>>
>>
>> Sorry, I just don't understand this.
>
>
> In some Flash LED devices one LED can be connected to one or more
> electric current outputs, which allows for multiplying the maximum
> current allowed for the LED. Each sub-LED is represented by a child
> node in the DT binding of the Flash LED device and it needs to declare
> which outputs it is connected to. In the example below the led-sources
> property is a two element array, which means that the flash LED device
> has two current outputs, and the bits signify if the LED is connected
> to the output.

Sounds like a regulator for which we already have bindings for and we
have a driver for regulator based LEDs (but no binding for it). Please
use the regulator binding.

> Do your doubts stem from the ambiguity of the word "current" or the
> form of the description itself is unclear? Probably there should be
> explicit explanation added that the size of the array depends on the
> number of current outputs of the flash LED device.

The size of the array and meaning of array indexes was not clear.

Rob

>
>
>>>   - label : The label for this LED.  If omitted, the label is
>>>     taken from the node name (excluding the unit address).
>>>
>>> @@ -33,6 +37,7 @@ system-status {
>>>
>>>   camera-flash {
>>>          label = "Flash";
>>> +       led-sources = <1 0>;
>>>          max-microamp = <50000>;
>>>          flash-max-microamp = <320000>;
>>>          flash-timeout-us = <500000>;
>>> --
>>> 1.7.9.5
>>>
>>
>
> --
> Best Regards,
> Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-12 13:52         ` Rob Herring
@ 2015-01-12 16:10           ` Jacek Anaszewski
  2015-01-12 16:55             ` Rob Herring
  0 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-12 16:10 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

On 01/12/2015 02:52 PM, Rob Herring wrote:
> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
> <j.anaszewski@samsung.com> wrote:
>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>
>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>> <j.anaszewski@samsung.com> wrote:
>>>>
>>>> Add a property for defining the device outputs the LED
>>>> represented by the DT child node is connected to.
>>>>
>>>> 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: Rob Herring <robh+dt@kernel.org>
>>>> Cc: Pawel Moll <pawel.moll@arm.com>
>>>> Cc: Mark Rutland <mark.rutland@arm.com>
>>>> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
>>>> Cc: Kumar Gala <galak@codeaurora.org>
>>>> ---
>>>>    Documentation/devicetree/bindings/leds/common.txt |    5 +++++
>>>>    1 file changed, 5 insertions(+)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/leds/common.txt
>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>> index a2c3f7a..29295bf 100644
>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>> @@ -1,6 +1,10 @@
>>>>    Common leds properties.
>>>>
>>>>    Optional properties for child nodes:
>>>> +- led-sources : Array of bits signifying the LED current regulator
>>>> outputs the
>>>> +               LED represented by the child node is connected to (1 -
>>>> the LED
>>>> +               is connected to the output, 0 - the LED isn't connected
>>>> to the
>>>> +               output).
>>>
>>>
>>> Sorry, I just don't understand this.
>>
>>
>> In some Flash LED devices one LED can be connected to one or more
>> electric current outputs, which allows for multiplying the maximum
>> current allowed for the LED. Each sub-LED is represented by a child
>> node in the DT binding of the Flash LED device and it needs to declare
>> which outputs it is connected to. In the example below the led-sources
>> property is a two element array, which means that the flash LED device
>> has two current outputs, and the bits signify if the LED is connected
>> to the output.
>
> Sounds like a regulator for which we already have bindings for and we
> have a driver for regulator based LEDs (but no binding for it).

Do you think of drivers/leds/leds-regulator.c driver? This driver just
allows for registering an arbitrary regulator device as a LED subsystem
device.

There are however devices that don't fall into this category, i.e. they
have many outputs, that can be connected to a single LED or to many LEDs
and the driver has to know what is the actual arrangement.

> Please use the regulator binding.

>> Do your doubts stem from the ambiguity of the word "current" or the
>> form of the description itself is unclear? Probably there should be
>> explicit explanation added that the size of the array depends on the
>> number of current outputs of the flash LED device.
>
> The size of the array and meaning of array indexes was not clear.

What about this:

led-sources : Array of connection states between all LED current
	      sources exposed by the device and this LED (1 - this LED
	      is connected to the current output with index N, 0 -
	      this LED isn't connected to the current output with
	      index N); the mapping of N-th element of the array to the
	      physical device output should be defined in the LED
	      driver binding.

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-12 16:10           ` Jacek Anaszewski
@ 2015-01-12 16:55             ` Rob Herring
  2015-01-12 17:06               ` Mark Brown
       [not found]               ` <CAL_JsqKpJtUG0G6g1GOuSVpc31oe-dp3qdrKJUE0upG-xRDFhA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 2 replies; 107+ messages in thread
From: Rob Herring @ 2015-01-12 16:55 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

Adding Mark B and Liam...

On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
<j.anaszewski@samsung.com> wrote:
> On 01/12/2015 02:52 PM, Rob Herring wrote:
>>
>> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
>> <j.anaszewski@samsung.com> wrote:
>>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>>> <j.anaszewski@samsung.com> wrote:
>>>>> Add a property for defining the device outputs the LED
>>>>> represented by the DT child node is connected to.

[...]

>>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>>> index a2c3f7a..29295bf 100644
>>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>>> @@ -1,6 +1,10 @@
>>>>>    Common leds properties.
>>>>>
>>>>>    Optional properties for child nodes:
>>>>> +- led-sources : Array of bits signifying the LED current regulator
>>>>> outputs the
>>>>> +               LED represented by the child node is connected to (1 -
>>>>> the LED
>>>>> +               is connected to the output, 0 - the LED isn't connected
>>>>> to the
>>>>> +               output).
>>>>
>>>>
>>>>
>>>> Sorry, I just don't understand this.
>>>
>>>
>>>
>>> In some Flash LED devices one LED can be connected to one or more
>>> electric current outputs, which allows for multiplying the maximum
>>> current allowed for the LED. Each sub-LED is represented by a child
>>> node in the DT binding of the Flash LED device and it needs to declare
>>> which outputs it is connected to. In the example below the led-sources
>>> property is a two element array, which means that the flash LED device
>>> has two current outputs, and the bits signify if the LED is connected
>>> to the output.
>>
>>
>> Sounds like a regulator for which we already have bindings for and we
>> have a driver for regulator based LEDs (but no binding for it).
>
>
> Do you think of drivers/leds/leds-regulator.c driver? This driver just
> allows for registering an arbitrary regulator device as a LED subsystem
> device.
>
> There are however devices that don't fall into this category, i.e. they
> have many outputs, that can be connected to a single LED or to many LEDs
> and the driver has to know what is the actual arrangement.

We may need to extend the regulator binding slightly and allow for
multiple phandles on a supply property, but wouldn't something like
this work:

led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;

The shared source is already supported by the regulator binding.

Rob

>
>> Please use the regulator binding.
>
>
>>> Do your doubts stem from the ambiguity of the word "current" or the
>>> form of the description itself is unclear? Probably there should be
>>> explicit explanation added that the size of the array depends on the
>>> number of current outputs of the flash LED device.
>>
>>
>> The size of the array and meaning of array indexes was not clear.
>
>
> What about this:
>
> led-sources : Array of connection states between all LED current
>               sources exposed by the device and this LED (1 - this LED
>               is connected to the current output with index N, 0 -
>               this LED isn't connected to the current output with
>               index N); the mapping of N-th element of the array to the
>               physical device output should be defined in the LED
>               driver binding.
>
>
> --
> Best Regards,
> Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-12 16:55             ` Rob Herring
@ 2015-01-12 17:06               ` Mark Brown
  2015-01-15 12:33                 ` Sylwester Nawrocki
       [not found]               ` <CAL_JsqKpJtUG0G6g1GOuSVpc31oe-dp3qdrKJUE0upG-xRDFhA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 107+ messages in thread
From: Mark Brown @ 2015-01-12 17:06 UTC (permalink / raw)
  To: Rob Herring
  Cc: Jacek Anaszewski, linux-leds, linux-media, linux-kernel,
	devicetree, Kyungmin Park, Bartlomiej Zolnierkiewicz,
	Pavel Machek, Bryan Wu, Richard Purdie, sakari.ailus,
	Sylwester Nawrocki, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Liam Girdwood

[-- Attachment #1: Type: text/plain, Size: 952 bytes --]

On Mon, Jan 12, 2015 at 10:55:29AM -0600, Rob Herring wrote:
> On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski

> > There are however devices that don't fall into this category, i.e. they
> > have many outputs, that can be connected to a single LED or to many LEDs
> > and the driver has to know what is the actual arrangement.

> We may need to extend the regulator binding slightly and allow for
> multiple phandles on a supply property, but wouldn't something like
> this work:

> led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;

> The shared source is already supported by the regulator binding.

What is the reasoning for this?  If a single supply is being supplied by
multiple regulators then in general those regulators will all know about
each other at a hardware level and so from a functional and software
point of view will effectively be one regulator.  If they don't/aren't
then they tend to interfere with each other.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-12 16:55             ` Rob Herring
@ 2015-01-13  8:42                   ` Jacek Anaszewski
       [not found]               ` <CAL_JsqKpJtUG0G6g1GOuSVpc31oe-dp3qdrKJUE0upG-xRDFhA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-13  8:42 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus-X3B1VOXEql0, Sylwester Nawrocki,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On 01/12/2015 05:55 PM, Rob Herring wrote:
> Adding Mark B and Liam...
>
> On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
> <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>> On 01/12/2015 02:52 PM, Rob Herring wrote:
>>>
>>> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
>>> <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>>>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>>>> <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>>>>>> Add a property for defining the device outputs the LED
>>>>>> represented by the DT child node is connected to.
>
> [...]
>
>>>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>>>> index a2c3f7a..29295bf 100644
>>>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>>>> @@ -1,6 +1,10 @@
>>>>>>     Common leds properties.
>>>>>>
>>>>>>     Optional properties for child nodes:
>>>>>> +- led-sources : Array of bits signifying the LED current regulator
>>>>>> outputs the
>>>>>> +               LED represented by the child node is connected to (1 -
>>>>>> the LED
>>>>>> +               is connected to the output, 0 - the LED isn't connected
>>>>>> to the
>>>>>> +               output).
>>>>>
>>>>>
>>>>>
>>>>> Sorry, I just don't understand this.
>>>>
>>>>
>>>>
>>>> In some Flash LED devices one LED can be connected to one or more
>>>> electric current outputs, which allows for multiplying the maximum
>>>> current allowed for the LED. Each sub-LED is represented by a child
>>>> node in the DT binding of the Flash LED device and it needs to declare
>>>> which outputs it is connected to. In the example below the led-sources
>>>> property is a two element array, which means that the flash LED device
>>>> has two current outputs, and the bits signify if the LED is connected
>>>> to the output.
>>>
>>>
>>> Sounds like a regulator for which we already have bindings for and we
>>> have a driver for regulator based LEDs (but no binding for it).
>>
>>
>> Do you think of drivers/leds/leds-regulator.c driver? This driver just
>> allows for registering an arbitrary regulator device as a LED subsystem
>> device.
>>
>> There are however devices that don't fall into this category, i.e. they
>> have many outputs, that can be connected to a single LED or to many LEDs
>> and the driver has to know what is the actual arrangement.
>
> We may need to extend the regulator binding slightly and allow for
> multiple phandles on a supply property, but wouldn't something like
> this work:
>
> led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>
> The shared source is already supported by the regulator binding.

I think that we shouldn't split the LED devices into power supply
providers and consumers as in case of generic regulators. From this
point of view a LED device current output is a provider and a discrete
LED element is a consumer. In this approach each discrete LED element
should have a related driver which is not how LED devices are being
handled in the LED subsystem, where there is a single binding for a LED
device and there is a single driver for it which creates separate LED
class devices for each LED connected to the LED device output. Each
discrete LED is represented by a child node in the LED device binding.

I am aware that it may be tempting to treat LED devices as common
regulators, but they have their specific features which gave a
reason for introducing LED class for them. Besides, there is already
drivers/leds/leds-regulator.c driver for LED devices which support only
turning on/off and setting brightness level.

In your proposition a separate regulator provider binding would have
to be created for each current output and a separate binding for
each discrete LED connected to the LED device. It would create
unnecessary noise in a dts file.

Moreover, using regulator binding implies that we want to treat it
as a sheer power supply for our device (which would be a discrete LED
element in this case), whereas LED devices provide more features like
blinking pattern and for flash LED devices - flash timeout, external
strobe and flash faults.

-- 
Best Regards,
Jacek Anaszewski
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
@ 2015-01-13  8:42                   ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-13  8:42 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On 01/12/2015 05:55 PM, Rob Herring wrote:
> Adding Mark B and Liam...
>
> On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
> <j.anaszewski@samsung.com> wrote:
>> On 01/12/2015 02:52 PM, Rob Herring wrote:
>>>
>>> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
>>> <j.anaszewski@samsung.com> wrote:
>>>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>> Add a property for defining the device outputs the LED
>>>>>> represented by the DT child node is connected to.
>
> [...]
>
>>>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>>>> index a2c3f7a..29295bf 100644
>>>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>>>> @@ -1,6 +1,10 @@
>>>>>>     Common leds properties.
>>>>>>
>>>>>>     Optional properties for child nodes:
>>>>>> +- led-sources : Array of bits signifying the LED current regulator
>>>>>> outputs the
>>>>>> +               LED represented by the child node is connected to (1 -
>>>>>> the LED
>>>>>> +               is connected to the output, 0 - the LED isn't connected
>>>>>> to the
>>>>>> +               output).
>>>>>
>>>>>
>>>>>
>>>>> Sorry, I just don't understand this.
>>>>
>>>>
>>>>
>>>> In some Flash LED devices one LED can be connected to one or more
>>>> electric current outputs, which allows for multiplying the maximum
>>>> current allowed for the LED. Each sub-LED is represented by a child
>>>> node in the DT binding of the Flash LED device and it needs to declare
>>>> which outputs it is connected to. In the example below the led-sources
>>>> property is a two element array, which means that the flash LED device
>>>> has two current outputs, and the bits signify if the LED is connected
>>>> to the output.
>>>
>>>
>>> Sounds like a regulator for which we already have bindings for and we
>>> have a driver for regulator based LEDs (but no binding for it).
>>
>>
>> Do you think of drivers/leds/leds-regulator.c driver? This driver just
>> allows for registering an arbitrary regulator device as a LED subsystem
>> device.
>>
>> There are however devices that don't fall into this category, i.e. they
>> have many outputs, that can be connected to a single LED or to many LEDs
>> and the driver has to know what is the actual arrangement.
>
> We may need to extend the regulator binding slightly and allow for
> multiple phandles on a supply property, but wouldn't something like
> this work:
>
> led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>
> The shared source is already supported by the regulator binding.

I think that we shouldn't split the LED devices into power supply
providers and consumers as in case of generic regulators. From this
point of view a LED device current output is a provider and a discrete
LED element is a consumer. In this approach each discrete LED element
should have a related driver which is not how LED devices are being
handled in the LED subsystem, where there is a single binding for a LED
device and there is a single driver for it which creates separate LED
class devices for each LED connected to the LED device output. Each
discrete LED is represented by a child node in the LED device binding.

I am aware that it may be tempting to treat LED devices as common
regulators, but they have their specific features which gave a
reason for introducing LED class for them. Besides, there is already
drivers/leds/leds-regulator.c driver for LED devices which support only
turning on/off and setting brightness level.

In your proposition a separate regulator provider binding would have
to be created for each current output and a separate binding for
each discrete LED connected to the LED device. It would create
unnecessary noise in a dts file.

Moreover, using regulator binding implies that we want to treat it
as a sheer power supply for our device (which would be a discrete LED
element in this case), whereas LED devices provide more features like
blinking pattern and for flash LED devices - flash timeout, external
strobe and flash faults.

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-12 17:06               ` Mark Brown
@ 2015-01-15 12:33                 ` Sylwester Nawrocki
  2015-01-15 14:37                   ` Rob Herring
  2015-01-15 21:03                   ` Pavel Machek
  0 siblings, 2 replies; 107+ messages in thread
From: Sylwester Nawrocki @ 2015-01-15 12:33 UTC (permalink / raw)
  To: Mark Brown, Rob Herring
  Cc: Jacek Anaszewski, linux-leds, linux-media, linux-kernel,
	devicetree, Kyungmin Park, Bartlomiej Zolnierkiewicz,
	Pavel Machek, Bryan Wu, Richard Purdie, sakari.ailus,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood

On 12/01/15 18:06, Mark Brown wrote:
> On Mon, Jan 12, 2015 at 10:55:29AM -0600, Rob Herring wrote:
>> > On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
>>> > > There are however devices that don't fall into this category, i.e. they
>>> > > have many outputs, that can be connected to a single LED or to many LEDs
>>> > > and the driver has to know what is the actual arrangement.
>> >
>> > We may need to extend the regulator binding slightly and allow for
>> > multiple phandles on a supply property, but wouldn't something like
>> > this work:
>> > led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>> > The shared source is already supported by the regulator binding.
>
> What is the reasoning for this?  If a single supply is being supplied by
> multiple regulators then in general those regulators will all know about
> each other at a hardware level and so from a functional and software
> point of view will effectively be one regulator.  If they don't/aren't
> then they tend to interfere with each other.

For LED current regulators like this one [1] we want to be able to 
communicate to the software the hardware wiring, e.g. if a single LED is 
connected to only one or both the current regulators.  The device needs 
to be programmed differently for each configuration, as shown on page 36 
of the datasheet [2].

Now, the LED DT binding describes the LEDs (current consumers) as child
nodes of the LED driver IC (current supplier), e.g. (from [3]):

pca9632@62 {
        compatible = "nxp,pca9632";
        #address-cells = <1>;
        #size-cells = <0>;
        reg = <0x62>;

        red@0 {
                label = "red";
                reg = <0>;
                linux,default-trigger = "none";
        };
        green@1 {
                label = "green";
                reg = <1>;
                linux,default-trigger = "none";
        };
	...
};

What is missing in this binding is the ability to tell that a single LED
is connected to more than one current source.

We could, for example adopt the multiple phandle in the supply property
scheme, but not use the kernel regulator API, e.g.

flash-led {
         compatible = "maxim,max77387";

         current-reg1 { // FLED1
                 led-output-id = <0>;
         };

         current-reg2 { // FLED2
                 led-output-id = <1>;
         };

         red_led {
                 led-supply = <&current-reg1>, <&current-reg2>;
         };
};

However my feeling is that it is unnecessarily complicated that way.

Perhaps we could use the 'reg' property to describe actual connections,
I'm not sure if it's better than a LED specific property, e.g.

max77387@52 {
        compatible = "nxp,max77387";
        #address-cells = <2>;
        #size-cells = <0>;
        reg = <0x52>;

	flash_led {
		reg = <1 1>;	
		...
	};	
};

[1] http://www.maximintegrated.com/en/products/power/led-drivers/MAX77387.html
[2] http://datasheets.maximintegrated.com/en/ds/MAX77387.pdf
[3] Documentation/devicetree/bindings/leds/pca963x.txt

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-13  8:42                   ` Jacek Anaszewski
  (?)
@ 2015-01-15 14:24                   ` Rob Herring
  2015-01-15 15:53                     ` Mark Brown
  2015-01-16  9:07                     ` Jacek Anaszewski
  -1 siblings, 2 replies; 107+ messages in thread
From: Rob Herring @ 2015-01-15 14:24 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On Tue, Jan 13, 2015 at 2:42 AM, Jacek Anaszewski
<j.anaszewski@samsung.com> wrote:
> On 01/12/2015 05:55 PM, Rob Herring wrote:
>>
>> Adding Mark B and Liam...
>>
>> On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
>> <j.anaszewski@samsung.com> wrote:
>>>
>>> On 01/12/2015 02:52 PM, Rob Herring wrote:
>>>>
>>>>
>>>> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
>>>> <j.anaszewski@samsung.com> wrote:
>>>>>
>>>>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>>>>
>>>>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>>
>>>>>>> Add a property for defining the device outputs the LED
>>>>>>> represented by the DT child node is connected to.
>>
>>
>> [...]
>>
>>>>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>> index a2c3f7a..29295bf 100644
>>>>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>> @@ -1,6 +1,10 @@
>>>>>>>     Common leds properties.
>>>>>>>
>>>>>>>     Optional properties for child nodes:
>>>>>>> +- led-sources : Array of bits signifying the LED current regulator
>>>>>>> outputs the
>>>>>>> +               LED represented by the child node is connected to (1
>>>>>>> -
>>>>>>> the LED
>>>>>>> +               is connected to the output, 0 - the LED isn't
>>>>>>> connected
>>>>>>> to the
>>>>>>> +               output).
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Sorry, I just don't understand this.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> In some Flash LED devices one LED can be connected to one or more
>>>>> electric current outputs, which allows for multiplying the maximum
>>>>> current allowed for the LED. Each sub-LED is represented by a child
>>>>> node in the DT binding of the Flash LED device and it needs to declare
>>>>> which outputs it is connected to. In the example below the led-sources
>>>>> property is a two element array, which means that the flash LED device
>>>>> has two current outputs, and the bits signify if the LED is connected
>>>>> to the output.
>>>>
>>>>
>>>>
>>>> Sounds like a regulator for which we already have bindings for and we
>>>> have a driver for regulator based LEDs (but no binding for it).
>>>
>>>
>>>
>>> Do you think of drivers/leds/leds-regulator.c driver? This driver just
>>> allows for registering an arbitrary regulator device as a LED subsystem
>>> device.
>>>
>>> There are however devices that don't fall into this category, i.e. they
>>> have many outputs, that can be connected to a single LED or to many LEDs
>>> and the driver has to know what is the actual arrangement.
>>
>>
>> We may need to extend the regulator binding slightly and allow for
>> multiple phandles on a supply property, but wouldn't something like
>> this work:
>>
>> led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>>
>> The shared source is already supported by the regulator binding.
>
>
> I think that we shouldn't split the LED devices into power supply
> providers and consumers as in case of generic regulators. From this
> point of view a LED device current output is a provider and a discrete
> LED element is a consumer. In this approach each discrete LED element
> should have a related driver which is not how LED devices are being
> handled in the LED subsystem, where there is a single binding for a LED
> device and there is a single driver for it which creates separate LED
> class devices for each LED connected to the LED device output. Each
> discrete LED is represented by a child node in the LED device binding.
>
> I am aware that it may be tempting to treat LED devices as common
> regulators, but they have their specific features which gave a
> reason for introducing LED class for them. Besides, there is already
> drivers/leds/leds-regulator.c driver for LED devices which support only
> turning on/off and setting brightness level.
>
> In your proposition a separate regulator provider binding would have
> to be created for each current output and a separate binding for
> each discrete LED connected to the LED device. It would create
> unnecessary noise in a dts file.
>
> Moreover, using regulator binding implies that we want to treat it
> as a sheer power supply for our device (which would be a discrete LED
> element in this case), whereas LED devices provide more features like
> blinking pattern and for flash LED devices - flash timeout, external
> strobe and flash faults.

Okay, fair enough. Please include some of this explanation in the
binding description.

I do still have some concerns about led-sources and whether it can
support other scenarios. It is very much tied to the parent node. Are
there any cases where we don't want the LEDs to be sub nodes? Perhaps
the LEDs are on a separate daughterboard from the driver/supply and we
can have different drivers. It's a stretch maybe. Or are there cases
where you need more information than just the connection?

Rob

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-15 12:33                 ` Sylwester Nawrocki
@ 2015-01-15 14:37                   ` Rob Herring
  2015-01-15 21:03                   ` Pavel Machek
  1 sibling, 0 replies; 107+ messages in thread
From: Rob Herring @ 2015-01-15 14:37 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: Mark Brown, Jacek Anaszewski, linux-leds, linux-media,
	linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Liam Girdwood

On Thu, Jan 15, 2015 at 6:33 AM, Sylwester Nawrocki
<s.nawrocki@samsung.com> wrote:
> On 12/01/15 18:06, Mark Brown wrote:
>> On Mon, Jan 12, 2015 at 10:55:29AM -0600, Rob Herring wrote:
>>> > On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
>>>> > > There are however devices that don't fall into this category, i.e. they
>>>> > > have many outputs, that can be connected to a single LED or to many LEDs
>>>> > > and the driver has to know what is the actual arrangement.
>>> >
>>> > We may need to extend the regulator binding slightly and allow for
>>> > multiple phandles on a supply property, but wouldn't something like
>>> > this work:
>>> > led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>>> > The shared source is already supported by the regulator binding.
>>
>> What is the reasoning for this?  If a single supply is being supplied by
>> multiple regulators then in general those regulators will all know about
>> each other at a hardware level and so from a functional and software
>> point of view will effectively be one regulator.  If they don't/aren't
>> then they tend to interfere with each other.
>
> For LED current regulators like this one [1] we want to be able to
> communicate to the software the hardware wiring, e.g. if a single LED is
> connected to only one or both the current regulators.  The device needs
> to be programmed differently for each configuration, as shown on page 36
> of the datasheet [2].
>
> Now, the LED DT binding describes the LEDs (current consumers) as child
> nodes of the LED driver IC (current supplier), e.g. (from [3]):
>
> pca9632@62 {
>         compatible = "nxp,pca9632";
>         #address-cells = <1>;
>         #size-cells = <0>;
>         reg = <0x62>;
>
>         red@0 {
>                 label = "red";
>                 reg = <0>;

This only works if you don't have sub blocks or different functions to
describe. I suppose you could add yet another level of nodes. This
feels like abuse of the reg property even though to use the reg
property is a frequent review comment.

OTOH, we don't need 2 ways to describe this.

>                 linux,default-trigger = "none";
>         };
>         green@1 {
>                 label = "green";
>                 reg = <1>;
>                 linux,default-trigger = "none";
>         };
>         ...
> };
>
> What is missing in this binding is the ability to tell that a single LED
> is connected to more than one current source.
>
> We could, for example adopt the multiple phandle in the supply property
> scheme, but not use the kernel regulator API, e.g.
>
> flash-led {
>          compatible = "maxim,max77387";
>
>          current-reg1 { // FLED1
>                  led-output-id = <0>;
>          };
>
>          current-reg2 { // FLED2
>                  led-output-id = <1>;
>          };
>
>          red_led {
>                  led-supply = <&current-reg1>, <&current-reg2>;
>          };
> };
>
> However my feeling is that it is unnecessarily complicated that way.

This example is not so complicated, but I already agreed on not using
regulators on the basis there are other properties of the driver
unique to LEDs.

> Perhaps we could use the 'reg' property to describe actual connections,
> I'm not sure if it's better than a LED specific property, e.g.
>
> max77387@52 {
>         compatible = "nxp,max77387";
>         #address-cells = <2>;
>         #size-cells = <0>;
>         reg = <0x52>;
>
>         flash_led {
>                 reg = <1 1>;

Don't you mean <0 1> as the values are the "address" which in this
case are the LED driver output indexes.

Rob

>                 ...
>         };
> };
>
> [1] http://www.maximintegrated.com/en/products/power/led-drivers/MAX77387.html
> [2] http://datasheets.maximintegrated.com/en/ds/MAX77387.pdf
> [3] Documentation/devicetree/bindings/leds/pca963x.txt

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-15 14:24                   ` Rob Herring
@ 2015-01-15 15:53                     ` Mark Brown
  2015-01-16  9:07                     ` Jacek Anaszewski
  1 sibling, 0 replies; 107+ messages in thread
From: Mark Brown @ 2015-01-15 15:53 UTC (permalink / raw)
  To: Rob Herring
  Cc: Jacek Anaszewski, linux-leds, linux-media, linux-kernel,
	devicetree, Kyungmin Park, Bartlomiej Zolnierkiewicz,
	Pavel Machek, Bryan Wu, Richard Purdie, sakari.ailus,
	Sylwester Nawrocki, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Liam Girdwood

[-- Attachment #1: Type: text/plain, Size: 1473 bytes --]

On Thu, Jan 15, 2015 at 08:24:26AM -0600, Rob Herring wrote:
> On Tue, Jan 13, 2015 at 2:42 AM, Jacek Anaszewski

> > I am aware that it may be tempting to treat LED devices as common
> > regulators, but they have their specific features which gave a
> > reason for introducing LED class for them. Besides, there is already
> > drivers/leds/leds-regulator.c driver for LED devices which support only
> > turning on/off and setting brightness level.
> >
> > In your proposition a separate regulator provider binding would have
> > to be created for each current output and a separate binding for
> > each discrete LED connected to the LED device. It would create
> > unnecessary noise in a dts file.
> >
> > Moreover, using regulator binding implies that we want to treat it
> > as a sheer power supply for our device (which would be a discrete LED
> > element in this case), whereas LED devices provide more features like
> > blinking pattern and for flash LED devices - flash timeout, external
> > strobe and flash faults.

> Okay, fair enough. Please include some of this explanation in the
> binding description.

Right, the other thing here is that these chips are not normally
designed with the goal that the various components be used separately -
I've seen devices where the startup and shutdown procedures involve
interleaved actions to the boost regulator and current sink for example.
Trying to insert an abstraction layer typically just makes life more
complex.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-15 12:33                 ` Sylwester Nawrocki
  2015-01-15 14:37                   ` Rob Herring
@ 2015-01-15 21:03                   ` Pavel Machek
  2015-01-16 10:17                       ` Sylwester Nawrocki
  1 sibling, 1 reply; 107+ messages in thread
From: Pavel Machek @ 2015-01-15 21:03 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: Mark Brown, Rob Herring, Jacek Anaszewski, linux-leds,
	linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Bryan Wu, Richard Purdie,
	sakari.ailus, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Liam Girdwood

Hi!

> Perhaps we could use the 'reg' property to describe actual connections,
> I'm not sure if it's better than a LED specific property, e.g.
> 
> max77387@52 {
>         compatible = "nxp,max77387";
>         #address-cells = <2>;
>         #size-cells = <0>;
>         reg = <0x52>;
> 
> 	flash_led {
> 		reg = <1 1>;	
> 		...
> 	};	
> };

Normally, reg property is <start length>, if I understand things
correctly? Would that be enough here, or would we be doing list of
outputs?

Thanks,
								Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-15 14:24                   ` Rob Herring
  2015-01-15 15:53                     ` Mark Brown
@ 2015-01-16  9:07                     ` Jacek Anaszewski
  2015-01-16 13:48                       ` Rob Herring
  1 sibling, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-16  9:07 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On 01/15/2015 03:24 PM, Rob Herring wrote:
> On Tue, Jan 13, 2015 at 2:42 AM, Jacek Anaszewski
> <j.anaszewski@samsung.com> wrote:
>> On 01/12/2015 05:55 PM, Rob Herring wrote:
>>>
>>> Adding Mark B and Liam...
>>>
>>> On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
>>> <j.anaszewski@samsung.com> wrote:
>>>>
>>>> On 01/12/2015 02:52 PM, Rob Herring wrote:
>>>>>
>>>>>
>>>>> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>
>>>>>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>>>>>
>>>>>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>>>
>>>>>>>> Add a property for defining the device outputs the LED
>>>>>>>> represented by the DT child node is connected to.
>>>
>>>
>>> [...]
>>>
>>>>>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>> index a2c3f7a..29295bf 100644
>>>>>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>> @@ -1,6 +1,10 @@
>>>>>>>>      Common leds properties.
>>>>>>>>
>>>>>>>>      Optional properties for child nodes:
>>>>>>>> +- led-sources : Array of bits signifying the LED current regulator
>>>>>>>> outputs the
>>>>>>>> +               LED represented by the child node is connected to (1
>>>>>>>> -
>>>>>>>> the LED
>>>>>>>> +               is connected to the output, 0 - the LED isn't
>>>>>>>> connected
>>>>>>>> to the
>>>>>>>> +               output).
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Sorry, I just don't understand this.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> In some Flash LED devices one LED can be connected to one or more
>>>>>> electric current outputs, which allows for multiplying the maximum
>>>>>> current allowed for the LED. Each sub-LED is represented by a child
>>>>>> node in the DT binding of the Flash LED device and it needs to declare
>>>>>> which outputs it is connected to. In the example below the led-sources
>>>>>> property is a two element array, which means that the flash LED device
>>>>>> has two current outputs, and the bits signify if the LED is connected
>>>>>> to the output.
>>>>>
>>>>>
>>>>>
>>>>> Sounds like a regulator for which we already have bindings for and we
>>>>> have a driver for regulator based LEDs (but no binding for it).
>>>>
>>>>
>>>>
>>>> Do you think of drivers/leds/leds-regulator.c driver? This driver just
>>>> allows for registering an arbitrary regulator device as a LED subsystem
>>>> device.
>>>>
>>>> There are however devices that don't fall into this category, i.e. they
>>>> have many outputs, that can be connected to a single LED or to many LEDs
>>>> and the driver has to know what is the actual arrangement.
>>>
>>>
>>> We may need to extend the regulator binding slightly and allow for
>>> multiple phandles on a supply property, but wouldn't something like
>>> this work:
>>>
>>> led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>>>
>>> The shared source is already supported by the regulator binding.
>>
>>
>> I think that we shouldn't split the LED devices into power supply
>> providers and consumers as in case of generic regulators. From this
>> point of view a LED device current output is a provider and a discrete
>> LED element is a consumer. In this approach each discrete LED element
>> should have a related driver which is not how LED devices are being
>> handled in the LED subsystem, where there is a single binding for a LED
>> device and there is a single driver for it which creates separate LED
>> class devices for each LED connected to the LED device output. Each
>> discrete LED is represented by a child node in the LED device binding.
>>
>> I am aware that it may be tempting to treat LED devices as common
>> regulators, but they have their specific features which gave a
>> reason for introducing LED class for them. Besides, there is already
>> drivers/leds/leds-regulator.c driver for LED devices which support only
>> turning on/off and setting brightness level.
>>
>> In your proposition a separate regulator provider binding would have
>> to be created for each current output and a separate binding for
>> each discrete LED connected to the LED device. It would create
>> unnecessary noise in a dts file.
>>
>> Moreover, using regulator binding implies that we want to treat it
>> as a sheer power supply for our device (which would be a discrete LED
>> element in this case), whereas LED devices provide more features like
>> blinking pattern and for flash LED devices - flash timeout, external
>> strobe and flash faults.
>
> Okay, fair enough. Please include some of this explanation in the
> binding description.
>
> I do still have some concerns about led-sources and whether it can
> support other scenarios. It is very much tied to the parent node. Are
> there any cases where we don't want the LEDs to be sub nodes? Perhaps
> the LEDs are on a separate daughterboard from the driver/supply and we
> can have different drivers. It's a stretch maybe.

I think it is. Such arrangements would introduce problems also to the
other existing bindings. Probably not only LED subsystem related ones.

> Or are there cases
> where you need more information than just the connection?

Currently I can't think of any.

Modified rough proposal of the description:


-Optional properties for child nodes:
+LED and flash LED devices provide the same basic functionality as
+current regulators, but extended with LED and flash LED specific 
+features like blinking patterns, flash timeout, flash faults and
+external flash strobe mode.
+
+Many LED devices expose more than one current output that can be
+connected to one or more discrete LED component. Since the arrangement
+of connections can influence the way of the LED device initialization,
+the LED components have to be tightly coupled with the LED device
+binding. They are represented in the form of its child nodes.
+
+Optional properties for child nodes (if a LED device exposes only one
+current output the properties can be placed directly in the LED device
+node):
+- led-sources : Array of connection states between all LED current
+               sources exposed by the device and this LED (1 - this LED
+               is connected to the current output with index N, 0 -
+               this LED isn't connected to the current output with
+               index N); the mapping of N-th element of the array to
+               the physical device output should be defined in the LED
+               driver binding.


-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-15 21:03                   ` Pavel Machek
@ 2015-01-16 10:17                       ` Sylwester Nawrocki
  0 siblings, 0 replies; 107+ messages in thread
From: Sylwester Nawrocki @ 2015-01-16 10:17 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Mark Brown, Rob Herring, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Bryan Wu, Richard Purdie,
	sakari.ailus-X3B1VOXEql0, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Liam Girdwood

Hi,

On 15/01/15 22:03, Pavel Machek wrote:
>> Perhaps we could use the 'reg' property to describe actual connections,
>> > I'm not sure if it's better than a LED specific property, e.g.
>> > 
>> > max77387@52 {
>> >         compatible = "nxp,max77387";
>> >         #address-cells = <2>;
>> >         #size-cells = <0>;
>> >         reg = <0x52>;
>> > 
>> > 	flash_led {
>> > 		reg = <1 1>;	
>> > 		...
>> > 	};	
>> > };
>
> Normally, reg property is <start length>, if I understand things
> correctly? Would that be enough here, or would we be doing list of
> outputs?

In general the exact meaning depends on value of the #address-cells and
#size-cells properties in the parent node.  In case as above #size-cells
is 0.  You can find exact explanation in [1], at page 25.

Anyway, the above example might an abuse of the simple bus. I thought more
about a list of outputs, but the indexes wouldn't be contiguous, e.g.

 curr. reg. outputs | "addres" value
--------------------------------
FLED2    FLED1      |  reg
--------------------+-----------
  0        1        | 0x00000001
  1        0        | 0x00010000
  1        1        | 0x00010001

But it might be not a good idea as Rob pointed out.

OTOH we could simply assign indices 1,2,3 to the above FLED1/2 output
combinations.

[1] https://www.power.org/wp-content/uploads/2012/06/Power_ePAPR_APPROVED_v1.1.pdf

--
Regards,
Sylwester
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
@ 2015-01-16 10:17                       ` Sylwester Nawrocki
  0 siblings, 0 replies; 107+ messages in thread
From: Sylwester Nawrocki @ 2015-01-16 10:17 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Mark Brown, Rob Herring, Jacek Anaszewski, linux-leds,
	linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Bryan Wu, Richard Purdie,
	sakari.ailus, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Liam Girdwood

Hi,

On 15/01/15 22:03, Pavel Machek wrote:
>> Perhaps we could use the 'reg' property to describe actual connections,
>> > I'm not sure if it's better than a LED specific property, e.g.
>> > 
>> > max77387@52 {
>> >         compatible = "nxp,max77387";
>> >         #address-cells = <2>;
>> >         #size-cells = <0>;
>> >         reg = <0x52>;
>> > 
>> > 	flash_led {
>> > 		reg = <1 1>;	
>> > 		...
>> > 	};	
>> > };
>
> Normally, reg property is <start length>, if I understand things
> correctly? Would that be enough here, or would we be doing list of
> outputs?

In general the exact meaning depends on value of the #address-cells and
#size-cells properties in the parent node.  In case as above #size-cells
is 0.  You can find exact explanation in [1], at page 25.

Anyway, the above example might an abuse of the simple bus. I thought more
about a list of outputs, but the indexes wouldn't be contiguous, e.g.

 curr. reg. outputs | "addres" value
--------------------------------
FLED2    FLED1      |  reg
--------------------+-----------
  0        1        | 0x00000001
  1        0        | 0x00010000
  1        1        | 0x00010001

But it might be not a good idea as Rob pointed out.

OTOH we could simply assign indices 1,2,3 to the above FLED1/2 output
combinations.

[1] https://www.power.org/wp-content/uploads/2012/06/Power_ePAPR_APPROVED_v1.1.pdf

--
Regards,
Sylwester

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-16  9:07                     ` Jacek Anaszewski
@ 2015-01-16 13:48                       ` Rob Herring
       [not found]                         ` <CAL_Jsq+EFWzs1HP1tVt6P=p=HZn2AtSPjp55YrmMQi_mE+kNfQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 107+ messages in thread
From: Rob Herring @ 2015-01-16 13:48 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On Fri, Jan 16, 2015 at 3:07 AM, Jacek Anaszewski
<j.anaszewski@samsung.com> wrote:
> On 01/15/2015 03:24 PM, Rob Herring wrote:
>>
>> On Tue, Jan 13, 2015 at 2:42 AM, Jacek Anaszewski
>> <j.anaszewski@samsung.com> wrote:
>>>
>>> On 01/12/2015 05:55 PM, Rob Herring wrote:
>>>>
>>>>
>>>> Adding Mark B and Liam...
>>>>
>>>> On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
>>>> <j.anaszewski@samsung.com> wrote:
>>>>>
>>>>>
>>>>> On 01/12/2015 02:52 PM, Rob Herring wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
>>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>>
>>>>>>>
>>>>>>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>>>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Add a property for defining the device outputs the LED
>>>>>>>>> represented by the DT child node is connected to.
>>>>
>>>>
>>>>
>>>> [...]
>>>>
>>>>>>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>> index a2c3f7a..29295bf 100644
>>>>>>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>> @@ -1,6 +1,10 @@
>>>>>>>>>      Common leds properties.
>>>>>>>>>
>>>>>>>>>      Optional properties for child nodes:
>>>>>>>>> +- led-sources : Array of bits signifying the LED current regulator
>>>>>>>>> outputs the
>>>>>>>>> +               LED represented by the child node is connected to
>>>>>>>>> (1
>>>>>>>>> -
>>>>>>>>> the LED
>>>>>>>>> +               is connected to the output, 0 - the LED isn't
>>>>>>>>> connected
>>>>>>>>> to the
>>>>>>>>> +               output).
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Sorry, I just don't understand this.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> In some Flash LED devices one LED can be connected to one or more
>>>>>>> electric current outputs, which allows for multiplying the maximum
>>>>>>> current allowed for the LED. Each sub-LED is represented by a child
>>>>>>> node in the DT binding of the Flash LED device and it needs to
>>>>>>> declare
>>>>>>> which outputs it is connected to. In the example below the
>>>>>>> led-sources
>>>>>>> property is a two element array, which means that the flash LED
>>>>>>> device
>>>>>>> has two current outputs, and the bits signify if the LED is connected
>>>>>>> to the output.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Sounds like a regulator for which we already have bindings for and we
>>>>>> have a driver for regulator based LEDs (but no binding for it).
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> Do you think of drivers/leds/leds-regulator.c driver? This driver just
>>>>> allows for registering an arbitrary regulator device as a LED subsystem
>>>>> device.
>>>>>
>>>>> There are however devices that don't fall into this category, i.e. they
>>>>> have many outputs, that can be connected to a single LED or to many
>>>>> LEDs
>>>>> and the driver has to know what is the actual arrangement.
>>>>
>>>>
>>>>
>>>> We may need to extend the regulator binding slightly and allow for
>>>> multiple phandles on a supply property, but wouldn't something like
>>>> this work:
>>>>
>>>> led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>>>>
>>>> The shared source is already supported by the regulator binding.
>>>
>>>
>>>
>>> I think that we shouldn't split the LED devices into power supply
>>> providers and consumers as in case of generic regulators. From this
>>> point of view a LED device current output is a provider and a discrete
>>> LED element is a consumer. In this approach each discrete LED element
>>> should have a related driver which is not how LED devices are being
>>> handled in the LED subsystem, where there is a single binding for a LED
>>> device and there is a single driver for it which creates separate LED
>>> class devices for each LED connected to the LED device output. Each
>>> discrete LED is represented by a child node in the LED device binding.
>>>
>>> I am aware that it may be tempting to treat LED devices as common
>>> regulators, but they have their specific features which gave a
>>> reason for introducing LED class for them. Besides, there is already
>>> drivers/leds/leds-regulator.c driver for LED devices which support only
>>> turning on/off and setting brightness level.
>>>
>>> In your proposition a separate regulator provider binding would have
>>> to be created for each current output and a separate binding for
>>> each discrete LED connected to the LED device. It would create
>>> unnecessary noise in a dts file.
>>>
>>> Moreover, using regulator binding implies that we want to treat it
>>> as a sheer power supply for our device (which would be a discrete LED
>>> element in this case), whereas LED devices provide more features like
>>> blinking pattern and for flash LED devices - flash timeout, external
>>> strobe and flash faults.
>>
>>
>> Okay, fair enough. Please include some of this explanation in the
>> binding description.
>>
>> I do still have some concerns about led-sources and whether it can
>> support other scenarios. It is very much tied to the parent node. Are
>> there any cases where we don't want the LEDs to be sub nodes? Perhaps
>> the LEDs are on a separate daughterboard from the driver/supply and we
>> can have different drivers. It's a stretch maybe.
>
>
> I think it is. Such arrangements would introduce problems also to the
> other existing bindings. Probably not only LED subsystem related ones.
>
>> Or are there cases
>> where you need more information than just the connection?
>
>
> Currently I can't think of any.
>
> Modified rough proposal of the description:
>
>
> -Optional properties for child nodes:
> +LED and flash LED devices provide the same basic functionality as
> +current regulators, but extended with LED and flash LED specific +features
> like blinking patterns, flash timeout, flash faults and
> +external flash strobe mode.
> +
> +Many LED devices expose more than one current output that can be
> +connected to one or more discrete LED component. Since the arrangement
> +of connections can influence the way of the LED device initialization,
> +the LED components have to be tightly coupled with the LED device
> +binding. They are represented in the form of its child nodes.
> +
> +Optional properties for child nodes (if a LED device exposes only one
> +current output the properties can be placed directly in the LED device
> +node):

Why special case 1 output case? Just always require a child node.

> +- led-sources : Array of connection states between all LED current
> +               sources exposed by the device and this LED (1 - this LED
> +               is connected to the current output with index N, 0 -
> +               this LED isn't connected to the current output with
> +               index N); the mapping of N-th element of the array to
> +               the physical device output should be defined in the LED
> +               driver binding.

I think this should be a list of connected output numbers rather than
effectively a bitmask.

You may want to add something like led-output-cnt or led-driver-cnt in
the parent so you know the max list size.

Rob

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-16 13:48                       ` Rob Herring
@ 2015-01-16 15:52                             ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-16 15:52 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus-X3B1VOXEql0, Sylwester Nawrocki,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On 01/16/2015 02:48 PM, Rob Herring wrote:
> On Fri, Jan 16, 2015 at 3:07 AM, Jacek Anaszewski
> <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>> On 01/15/2015 03:24 PM, Rob Herring wrote:
>>>
>>> On Tue, Jan 13, 2015 at 2:42 AM, Jacek Anaszewski
>>> <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>>>>
>>>> On 01/12/2015 05:55 PM, Rob Herring wrote:
>>>>>
>>>>>
>>>>> Adding Mark B and Liam...
>>>>>
>>>>> On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
>>>>> <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>>>>>>
>>>>>>
>>>>>> On 01/12/2015 02:52 PM, Rob Herring wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
>>>>>>> <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>>>>>>>> <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Add a property for defining the device outputs the LED
>>>>>>>>>> represented by the DT child node is connected to.
>>>>>
>>>>>
>>>>>
>>>>> [...]
>>>>>
>>>>>>>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>>> index a2c3f7a..29295bf 100644
>>>>>>>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>>> @@ -1,6 +1,10 @@
>>>>>>>>>>       Common leds properties.
>>>>>>>>>>
>>>>>>>>>>       Optional properties for child nodes:
>>>>>>>>>> +- led-sources : Array of bits signifying the LED current regulator
>>>>>>>>>> outputs the
>>>>>>>>>> +               LED represented by the child node is connected to
>>>>>>>>>> (1
>>>>>>>>>> -
>>>>>>>>>> the LED
>>>>>>>>>> +               is connected to the output, 0 - the LED isn't
>>>>>>>>>> connected
>>>>>>>>>> to the
>>>>>>>>>> +               output).
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Sorry, I just don't understand this.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> In some Flash LED devices one LED can be connected to one or more
>>>>>>>> electric current outputs, which allows for multiplying the maximum
>>>>>>>> current allowed for the LED. Each sub-LED is represented by a child
>>>>>>>> node in the DT binding of the Flash LED device and it needs to
>>>>>>>> declare
>>>>>>>> which outputs it is connected to. In the example below the
>>>>>>>> led-sources
>>>>>>>> property is a two element array, which means that the flash LED
>>>>>>>> device
>>>>>>>> has two current outputs, and the bits signify if the LED is connected
>>>>>>>> to the output.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Sounds like a regulator for which we already have bindings for and we
>>>>>>> have a driver for regulator based LEDs (but no binding for it).
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Do you think of drivers/leds/leds-regulator.c driver? This driver just
>>>>>> allows for registering an arbitrary regulator device as a LED subsystem
>>>>>> device.
>>>>>>
>>>>>> There are however devices that don't fall into this category, i.e. they
>>>>>> have many outputs, that can be connected to a single LED or to many
>>>>>> LEDs
>>>>>> and the driver has to know what is the actual arrangement.
>>>>>
>>>>>
>>>>>
>>>>> We may need to extend the regulator binding slightly and allow for
>>>>> multiple phandles on a supply property, but wouldn't something like
>>>>> this work:
>>>>>
>>>>> led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>>>>>
>>>>> The shared source is already supported by the regulator binding.
>>>>
>>>>
>>>>
>>>> I think that we shouldn't split the LED devices into power supply
>>>> providers and consumers as in case of generic regulators. From this
>>>> point of view a LED device current output is a provider and a discrete
>>>> LED element is a consumer. In this approach each discrete LED element
>>>> should have a related driver which is not how LED devices are being
>>>> handled in the LED subsystem, where there is a single binding for a LED
>>>> device and there is a single driver for it which creates separate LED
>>>> class devices for each LED connected to the LED device output. Each
>>>> discrete LED is represented by a child node in the LED device binding.
>>>>
>>>> I am aware that it may be tempting to treat LED devices as common
>>>> regulators, but they have their specific features which gave a
>>>> reason for introducing LED class for them. Besides, there is already
>>>> drivers/leds/leds-regulator.c driver for LED devices which support only
>>>> turning on/off and setting brightness level.
>>>>
>>>> In your proposition a separate regulator provider binding would have
>>>> to be created for each current output and a separate binding for
>>>> each discrete LED connected to the LED device. It would create
>>>> unnecessary noise in a dts file.
>>>>
>>>> Moreover, using regulator binding implies that we want to treat it
>>>> as a sheer power supply for our device (which would be a discrete LED
>>>> element in this case), whereas LED devices provide more features like
>>>> blinking pattern and for flash LED devices - flash timeout, external
>>>> strobe and flash faults.
>>>
>>>
>>> Okay, fair enough. Please include some of this explanation in the
>>> binding description.
>>>
>>> I do still have some concerns about led-sources and whether it can
>>> support other scenarios. It is very much tied to the parent node. Are
>>> there any cases where we don't want the LEDs to be sub nodes? Perhaps
>>> the LEDs are on a separate daughterboard from the driver/supply and we
>>> can have different drivers. It's a stretch maybe.
>>
>>
>> I think it is. Such arrangements would introduce problems also to the
>> other existing bindings. Probably not only LED subsystem related ones.
>>
>>> Or are there cases
>>> where you need more information than just the connection?
>>
>>
>> Currently I can't think of any.
>>
>> Modified rough proposal of the description:
>>
>>
>> -Optional properties for child nodes:
>> +LED and flash LED devices provide the same basic functionality as
>> +current regulators, but extended with LED and flash LED specific +features
>> like blinking patterns, flash timeout, flash faults and
>> +external flash strobe mode.
>> +
>> +Many LED devices expose more than one current output that can be
>> +connected to one or more discrete LED component. Since the arrangement
>> +of connections can influence the way of the LED device initialization,
>> +the LED components have to be tightly coupled with the LED device
>> +binding. They are represented in the form of its child nodes.
>> +
>> +Optional properties for child nodes (if a LED device exposes only one
>> +current output the properties can be placed directly in the LED device
>> +node):
>
> Why special case 1 output case? Just always require a child node.

OK.

>> +- led-sources : Array of connection states between all LED current
>> +               sources exposed by the device and this LED (1 - this LED
>> +               is connected to the current output with index N, 0 -
>> +               this LED isn't connected to the current output with
>> +               index N); the mapping of N-th element of the array to
>> +               the physical device output should be defined in the LED
>> +               driver binding.
>
> I think this should be a list of connected output numbers rather than
> effectively a bitmask.
>
> You may want to add something like led-output-cnt or led-driver-cnt in
> the parent so you know the max list size.

Why should we need this? The number of current outputs exposed by the
device is fixed and can be specified in a LED device bindings
documentation.

-- 
Best Regards,
Jacek Anaszewski
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
@ 2015-01-16 15:52                             ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-16 15:52 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On 01/16/2015 02:48 PM, Rob Herring wrote:
> On Fri, Jan 16, 2015 at 3:07 AM, Jacek Anaszewski
> <j.anaszewski@samsung.com> wrote:
>> On 01/15/2015 03:24 PM, Rob Herring wrote:
>>>
>>> On Tue, Jan 13, 2015 at 2:42 AM, Jacek Anaszewski
>>> <j.anaszewski@samsung.com> wrote:
>>>>
>>>> On 01/12/2015 05:55 PM, Rob Herring wrote:
>>>>>
>>>>>
>>>>> Adding Mark B and Liam...
>>>>>
>>>>> On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>
>>>>>>
>>>>>> On 01/12/2015 02:52 PM, Rob Herring wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
>>>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>>>>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Add a property for defining the device outputs the LED
>>>>>>>>>> represented by the DT child node is connected to.
>>>>>
>>>>>
>>>>>
>>>>> [...]
>>>>>
>>>>>>>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>>> index a2c3f7a..29295bf 100644
>>>>>>>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>>> @@ -1,6 +1,10 @@
>>>>>>>>>>       Common leds properties.
>>>>>>>>>>
>>>>>>>>>>       Optional properties for child nodes:
>>>>>>>>>> +- led-sources : Array of bits signifying the LED current regulator
>>>>>>>>>> outputs the
>>>>>>>>>> +               LED represented by the child node is connected to
>>>>>>>>>> (1
>>>>>>>>>> -
>>>>>>>>>> the LED
>>>>>>>>>> +               is connected to the output, 0 - the LED isn't
>>>>>>>>>> connected
>>>>>>>>>> to the
>>>>>>>>>> +               output).
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Sorry, I just don't understand this.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> In some Flash LED devices one LED can be connected to one or more
>>>>>>>> electric current outputs, which allows for multiplying the maximum
>>>>>>>> current allowed for the LED. Each sub-LED is represented by a child
>>>>>>>> node in the DT binding of the Flash LED device and it needs to
>>>>>>>> declare
>>>>>>>> which outputs it is connected to. In the example below the
>>>>>>>> led-sources
>>>>>>>> property is a two element array, which means that the flash LED
>>>>>>>> device
>>>>>>>> has two current outputs, and the bits signify if the LED is connected
>>>>>>>> to the output.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Sounds like a regulator for which we already have bindings for and we
>>>>>>> have a driver for regulator based LEDs (but no binding for it).
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> Do you think of drivers/leds/leds-regulator.c driver? This driver just
>>>>>> allows for registering an arbitrary regulator device as a LED subsystem
>>>>>> device.
>>>>>>
>>>>>> There are however devices that don't fall into this category, i.e. they
>>>>>> have many outputs, that can be connected to a single LED or to many
>>>>>> LEDs
>>>>>> and the driver has to know what is the actual arrangement.
>>>>>
>>>>>
>>>>>
>>>>> We may need to extend the regulator binding slightly and allow for
>>>>> multiple phandles on a supply property, but wouldn't something like
>>>>> this work:
>>>>>
>>>>> led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>>>>>
>>>>> The shared source is already supported by the regulator binding.
>>>>
>>>>
>>>>
>>>> I think that we shouldn't split the LED devices into power supply
>>>> providers and consumers as in case of generic regulators. From this
>>>> point of view a LED device current output is a provider and a discrete
>>>> LED element is a consumer. In this approach each discrete LED element
>>>> should have a related driver which is not how LED devices are being
>>>> handled in the LED subsystem, where there is a single binding for a LED
>>>> device and there is a single driver for it which creates separate LED
>>>> class devices for each LED connected to the LED device output. Each
>>>> discrete LED is represented by a child node in the LED device binding.
>>>>
>>>> I am aware that it may be tempting to treat LED devices as common
>>>> regulators, but they have their specific features which gave a
>>>> reason for introducing LED class for them. Besides, there is already
>>>> drivers/leds/leds-regulator.c driver for LED devices which support only
>>>> turning on/off and setting brightness level.
>>>>
>>>> In your proposition a separate regulator provider binding would have
>>>> to be created for each current output and a separate binding for
>>>> each discrete LED connected to the LED device. It would create
>>>> unnecessary noise in a dts file.
>>>>
>>>> Moreover, using regulator binding implies that we want to treat it
>>>> as a sheer power supply for our device (which would be a discrete LED
>>>> element in this case), whereas LED devices provide more features like
>>>> blinking pattern and for flash LED devices - flash timeout, external
>>>> strobe and flash faults.
>>>
>>>
>>> Okay, fair enough. Please include some of this explanation in the
>>> binding description.
>>>
>>> I do still have some concerns about led-sources and whether it can
>>> support other scenarios. It is very much tied to the parent node. Are
>>> there any cases where we don't want the LEDs to be sub nodes? Perhaps
>>> the LEDs are on a separate daughterboard from the driver/supply and we
>>> can have different drivers. It's a stretch maybe.
>>
>>
>> I think it is. Such arrangements would introduce problems also to the
>> other existing bindings. Probably not only LED subsystem related ones.
>>
>>> Or are there cases
>>> where you need more information than just the connection?
>>
>>
>> Currently I can't think of any.
>>
>> Modified rough proposal of the description:
>>
>>
>> -Optional properties for child nodes:
>> +LED and flash LED devices provide the same basic functionality as
>> +current regulators, but extended with LED and flash LED specific +features
>> like blinking patterns, flash timeout, flash faults and
>> +external flash strobe mode.
>> +
>> +Many LED devices expose more than one current output that can be
>> +connected to one or more discrete LED component. Since the arrangement
>> +of connections can influence the way of the LED device initialization,
>> +the LED components have to be tightly coupled with the LED device
>> +binding. They are represented in the form of its child nodes.
>> +
>> +Optional properties for child nodes (if a LED device exposes only one
>> +current output the properties can be placed directly in the LED device
>> +node):
>
> Why special case 1 output case? Just always require a child node.

OK.

>> +- led-sources : Array of connection states between all LED current
>> +               sources exposed by the device and this LED (1 - this LED
>> +               is connected to the current output with index N, 0 -
>> +               this LED isn't connected to the current output with
>> +               index N); the mapping of N-th element of the array to
>> +               the physical device output should be defined in the LED
>> +               driver binding.
>
> I think this should be a list of connected output numbers rather than
> effectively a bitmask.
>
> You may want to add something like led-output-cnt or led-driver-cnt in
> the parent so you know the max list size.

Why should we need this? The number of current outputs exposed by the
device is fixed and can be specified in a LED device bindings
documentation.

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros
  2015-01-09 15:22 ` [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros Jacek Anaszewski
  2015-01-09 17:43   ` Pavel Machek
@ 2015-01-20 11:12   ` Lee Jones
  2015-01-20 12:53     ` Jacek Anaszewski
  1 sibling, 1 reply; 107+ messages in thread
From: Lee Jones @ 2015-01-20 11:12 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On Fri, 09 Jan 2015, Jacek Anaszewski wrote:

> Add macros for max77693 led part related binding.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Lee Jones <lee.jones@linaro.org>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  include/dt-bindings/mfd/max77693.h |   21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
>  create mode 100644 include/dt-bindings/mfd/max77693.h
> 
> diff --git a/include/dt-bindings/mfd/max77693.h b/include/dt-bindings/mfd/max77693.h
> new file mode 100644
> index 0000000..f53e197
> --- /dev/null
> +++ b/include/dt-bindings/mfd/max77693.h
> @@ -0,0 +1,21 @@
> +/*
> + * This header provides macros for MAX77693 device binding
> + *
> + * Copyright (C) 2014, Samsung Electronics Co., Ltd.
> + *
> + * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
> + */
> +
> +#ifndef __DT_BINDINGS_MAX77693_H__
> +#define __DT_BINDINGS_MAX77693_H
> +
> +/* External trigger type */
> +#define MAX77693_LED_TRIG_TYPE_EDGE	0
> +#define MAX77693_LED_TRIG_TYPE_LEVEL	1
> +
> +/* Boost modes */
> +#define MAX77693_LED_BOOST_OFF		0
> +#define MAX77693_LED_BOOST_ADAPTIVE	1
> +#define MAX77693_LED_BOOST_FIXED	2
> +
> +#endif /* __DT_BINDINGS_MAX77693_H */

These look fairly generic.  Do generic LED defines already exist?  If
not, can they?

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers
  2015-01-09 15:22 ` [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers Jacek Anaszewski
@ 2015-01-20 11:13       ` Lee Jones
       [not found]   ` <1420816989-1808-6-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  1 sibling, 0 replies; 107+ messages in thread
From: Lee Jones @ 2015-01-20 11:13 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ, pavel-+ZI9xUNit7I,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Chanwoo Choi

On Fri, 09 Jan 2015, Jacek Anaszewski wrote:

> Change flash cell identifiers from max77693-flash to max77693-led
> to avoid confusion with NOR/NAND Flash.

This is okay by me, but aren't these ABI yet?

> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  drivers/mfd/max77693.c |    4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
> index a159593..cb14afa 100644
> --- a/drivers/mfd/max77693.c
> +++ b/drivers/mfd/max77693.c
> @@ -53,8 +53,8 @@ static const struct mfd_cell max77693_devs[] = {
>  		.of_compatible = "maxim,max77693-haptic",
>  	},
>  	{
> -		.name = "max77693-flash",
> -		.of_compatible = "maxim,max77693-flash",
> +		.name = "max77693-led",
> +		.of_compatible = "maxim,max77693-led",
>  	},
>  };
>  

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers
@ 2015-01-20 11:13       ` Lee Jones
  0 siblings, 0 replies; 107+ messages in thread
From: Lee Jones @ 2015-01-20 11:13 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On Fri, 09 Jan 2015, Jacek Anaszewski wrote:

> Change flash cell identifiers from max77693-flash to max77693-led
> to avoid confusion with NOR/NAND Flash.

This is okay by me, but aren't these ABI yet?

> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Cc: Lee Jones <lee.jones@linaro.org>
> ---
>  drivers/mfd/max77693.c |    4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
> index a159593..cb14afa 100644
> --- a/drivers/mfd/max77693.c
> +++ b/drivers/mfd/max77693.c
> @@ -53,8 +53,8 @@ static const struct mfd_cell max77693_devs[] = {
>  		.of_compatible = "maxim,max77693-haptic",
>  	},
>  	{
> -		.name = "max77693-flash",
> -		.of_compatible = "maxim,max77693-flash",
> +		.name = "max77693-led",
> +		.of_compatible = "maxim,max77693-led",
>  	},
>  };
>  

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 06/19] mfd: max77693: modifications around max77693_led_platform_data
  2015-01-09 15:22 ` [PATCH/RFC v10 06/19] mfd: max77693: modifications around max77693_led_platform_data Jacek Anaszewski
@ 2015-01-20 11:15       ` Lee Jones
       [not found]   ` <1420816989-1808-7-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  1 sibling, 0 replies; 107+ messages in thread
From: Lee Jones @ 2015-01-20 11:15 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ, pavel-+ZI9xUNit7I,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Chanwoo Choi

On Fri, 09 Jan 2015, Jacek Anaszewski wrote:

> 1. Rename max77693_led_platform_data to max77693_led_config_data to
>    avoid making impression that the led driver expects a board file -
>    it relies on Device Tree data.
> 2. Remove fleds array, as the DT binding design has changed
> 3. Add "label" array for Device Tree strings with the name of a LED device
> 4. Make flash_timeout a two element array, for caching the sub-led
>    related flash timeout.
> 5. Remove trigger array as the related data will not be provided
>    in the DT binding

Code looks fine, and I'm sure you've tested this thoroughly.

I'm slightly concerned about current users though.  Are there any?  Is
this patch-set fully bisectable?

> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  include/linux/mfd/max77693.h |    9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/include/linux/mfd/max77693.h b/include/linux/mfd/max77693.h
> index f0b6585..c1ccb13 100644
> --- a/include/linux/mfd/max77693.h
> +++ b/include/linux/mfd/max77693.h
> @@ -87,17 +87,16 @@ enum max77693_led_boost_mode {
>  	MAX77693_LED_BOOST_FIXED,
>  };
>  
> -struct max77693_led_platform_data {
> -	u32 fleds[2];
> +struct max77693_led_config_data {
> +	const char *label[2];
>  	u32 iout_torch[2];
>  	u32 iout_flash[2];
> -	u32 trigger[2];
> -	u32 trigger_type[2];
> +	u32 flash_timeout[2];
>  	u32 num_leds;
>  	u32 boost_mode;
> -	u32 flash_timeout;
>  	u32 boost_vout;
>  	u32 low_vsys;
> +	u32 trigger_type;
>  };
>  
>  /* MAX77693 */

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 06/19] mfd: max77693: modifications around max77693_led_platform_data
@ 2015-01-20 11:15       ` Lee Jones
  0 siblings, 0 replies; 107+ messages in thread
From: Lee Jones @ 2015-01-20 11:15 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On Fri, 09 Jan 2015, Jacek Anaszewski wrote:

> 1. Rename max77693_led_platform_data to max77693_led_config_data to
>    avoid making impression that the led driver expects a board file -
>    it relies on Device Tree data.
> 2. Remove fleds array, as the DT binding design has changed
> 3. Add "label" array for Device Tree strings with the name of a LED device
> 4. Make flash_timeout a two element array, for caching the sub-led
>    related flash timeout.
> 5. Remove trigger array as the related data will not be provided
>    in the DT binding

Code looks fine, and I'm sure you've tested this thoroughly.

I'm slightly concerned about current users though.  Are there any?  Is
this patch-set fully bisectable?

> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Cc: Lee Jones <lee.jones@linaro.org>
> ---
>  include/linux/mfd/max77693.h |    9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/include/linux/mfd/max77693.h b/include/linux/mfd/max77693.h
> index f0b6585..c1ccb13 100644
> --- a/include/linux/mfd/max77693.h
> +++ b/include/linux/mfd/max77693.h
> @@ -87,17 +87,16 @@ enum max77693_led_boost_mode {
>  	MAX77693_LED_BOOST_FIXED,
>  };
>  
> -struct max77693_led_platform_data {
> -	u32 fleds[2];
> +struct max77693_led_config_data {
> +	const char *label[2];
>  	u32 iout_torch[2];
>  	u32 iout_flash[2];
> -	u32 trigger[2];
> -	u32 trigger_type[2];
> +	u32 flash_timeout[2];
>  	u32 num_leds;
>  	u32 boost_mode;
> -	u32 flash_timeout;
>  	u32 boost_vout;
>  	u32 low_vsys;
> +	u32 trigger_type;
>  };
>  
>  /* MAX77693 */

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros
  2015-01-09 15:22 ` [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros Jacek Anaszewski
  2015-01-09 17:59   ` Pavel Machek
@ 2015-01-20 11:17   ` Lee Jones
  2015-01-20 13:01     ` Jacek Anaszewski
  1 sibling, 1 reply; 107+ messages in thread
From: Lee Jones @ 2015-01-20 11:17 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On Fri, 09 Jan 2015, Jacek Anaszewski wrote:

> Modify FLASH_EN_SHIFT and TORCH_EN_SHIFT macros to work properly
> when passed enum max77693_fled values (0 for FLED1 and 1 for FLED2)
> from leds-max77693 driver.

Off-by-one ay?  Wasn't the original code tested?

> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Cc: Lee Jones <lee.jones@linaro.org>
> ---
>  include/linux/mfd/max77693-private.h |    4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
> index 08dae01..01799a9 100644
> --- a/include/linux/mfd/max77693-private.h
> +++ b/include/linux/mfd/max77693-private.h
> @@ -113,8 +113,8 @@ enum max77693_pmic_reg {
>  #define FLASH_EN_FLASH		0x1
>  #define FLASH_EN_TORCH		0x2
>  #define FLASH_EN_ON		0x3
> -#define FLASH_EN_SHIFT(x)	(6 - ((x) - 1) * 2)
> -#define TORCH_EN_SHIFT(x)	(2 - ((x) - 1) * 2)
> +#define FLASH_EN_SHIFT(x)	(6 - (x) * 2)
> +#define TORCH_EN_SHIFT(x)	(2 - (x) * 2)
>  
>  /* MAX77693 MAX_FLASH1 register */
>  #define MAX_FLASH1_MAX_FL_EN	0x80

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693
  2015-01-09 15:22 ` [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693 Jacek Anaszewski
  2015-01-09 17:52   ` Pavel Machek
@ 2015-01-20 11:21   ` Lee Jones
  2015-01-20 14:36     ` Jacek Anaszewski
  1 sibling, 1 reply; 107+ messages in thread
From: Lee Jones @ 2015-01-20 11:21 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Andrzej Hajda, Chanwoo Choi, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala

On Fri, 09 Jan 2015, Jacek Anaszewski wrote:

> This patch adds device tree binding documentation for
> the flash cell of the Maxim max77693 multifunctional device.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Lee Jones <lee.jones@linaro.org>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Cc: Bryan Wu <cooloney@gmail.com>
> Cc: Richard Purdie <rpurdie@rpsys.net>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: Kumar Gala <galak@codeaurora.org>
> ---
>  Documentation/devicetree/bindings/mfd/max77693.txt |   69 ++++++++++++++++++++
>  1 file changed, 69 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
> index 01e9f30..ef184f0 100644
> --- a/Documentation/devicetree/bindings/mfd/max77693.txt
> +++ b/Documentation/devicetree/bindings/mfd/max77693.txt
> @@ -41,7 +41,52 @@ Optional properties:
>  	 To get more informations, please refer to documentaion.
>  	[*] refer Documentation/devicetree/bindings/pwm/pwm.txt
>  
> +- led : the LED submodule device node
> +
> +There are two led outputs available - fled1 and fled2. Each of them can
> +control a separate led or they can be connected together to double
> +the maximum current for a single connected led. One led is represented
> +by one child node.
> +
> +Required properties:
> +- compatible : Must be "maxim,max77693-led".
> +
> +Optional properties:
> +- maxim,trigger-type : Flash trigger type.
> +	Possible trigger types:
> +		MAX77693_LED_TRIG_TYPE_EDGE - Rising edge of the signal triggers
> +			the flash,
> +		MAX77693_LED_TRIG_TYPE_LEVEL - Strobe pulse length controls
> +			duration of the flash.

I think you should represent the proper values here instead of the
defines.

> +- maxim,boost-mode :
> +	In boost mode the device can produce up to 1.2A of total current
> +	on both outputs. The maximum current on each output is reduced
> +	to 625mA then. If not enabled explicitly, boost setting defaults to
> +	MAX77693_LED_BOOST_FIXED in case both current sources are used.
> +	Possible values:
> +		MAX77693_LED_BOOST_OFF - no boost,
> +		MAX77693_LED_BOOST_ADAPTIVE - adaptive mode,
> +		MAX77693_LED_BOOST_FIXED - fixed mode.

Same here.

> +- maxim,boost-vout : Output voltage of the boost module in millivolts.

-mvout?
-microvout?

> +- maxim,vsys-min : Low input voltage level in millivolts. Flash is not fired
> +	if chip estimates that system voltage could drop below this level due
> +	to flash power consumption.

mvsys?
microvsys?

> +Required properties of the LED child node:
> +- label : see Documentation/devicetree/bindings/leds/common.txt
> +- led-sources : see Documentation/devicetree/bindings/leds/common.txt
> +
> +Optional properties of the LED child node:
> +- max-microamp : see Documentation/devicetree/bindings/leds/common.txt
> +		Range: 15625 - 250000
> +- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
> +		Range: 15625 - 1000000
> +- flash-timeout-us : see Documentation/devicetree/bindings/leds/common.txt
> +		Range: 62500 - 1000000
> +
>  Example:
> +#include <dt-bindings/mfd/max77693.h>
> +
>  	max77693@66 {
>  		compatible = "maxim,max77693";
>  		reg = <0x66>;
> @@ -73,4 +118,28 @@ Example:
>  			pwms = <&pwm 0 40000 0>;
>  			pwm-names = "haptic";
>  		};
> +
> +		led {
> +			compatible = "maxim,max77693-led";
> +			maxim,trigger-type = <MAX77693_LED_TRIG_TYPE_LEVEL>;
> +			maxim,boost-mode = <MAX77693_LED_BOOST_FIXED>;
> +			maxim,boost-vout = <5000>;
> +			maxim,vsys-min = <2400>;
> +
> +			camera1_flash: led1 {
> +				label = "max77693-flash1";
> +				led-sources = <1 0>;
> +				max-microamp = <250000>;
> +				flash-max-microamp = <625000>;
> +				flash-timeout-us = <1000000>;
> +			};
> +
> +			camera2_flash: led2 {
> +				label = "max77693-flash2";
> +				led-sources = <0 1>;
> +				max-microamp = <250000>;
> +				flash-max-microamp = <625000>;
> +				flash-timeout-us = <1000000>;
> +			};
> +		};
>  	};

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros
  2015-01-20 11:12   ` Lee Jones
@ 2015-01-20 12:53     ` Jacek Anaszewski
  2015-01-28  8:52       ` Sakari Ailus
  0 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-20 12:53 UTC (permalink / raw)
  To: Lee Jones
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On 01/20/2015 12:12 PM, Lee Jones wrote:
> On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
>
>> Add macros for max77693 led part related binding.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Cc: Chanwoo Choi <cw00.choi@samsung.com>
>> ---
>>   include/dt-bindings/mfd/max77693.h |   21 +++++++++++++++++++++
>>   1 file changed, 21 insertions(+)
>>   create mode 100644 include/dt-bindings/mfd/max77693.h
>>
>> diff --git a/include/dt-bindings/mfd/max77693.h b/include/dt-bindings/mfd/max77693.h
>> new file mode 100644
>> index 0000000..f53e197
>> --- /dev/null
>> +++ b/include/dt-bindings/mfd/max77693.h
>> @@ -0,0 +1,21 @@
>> +/*
>> + * This header provides macros for MAX77693 device binding
>> + *
>> + * Copyright (C) 2014, Samsung Electronics Co., Ltd.
>> + *
>> + * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
>> + */
>> +
>> +#ifndef __DT_BINDINGS_MAX77693_H__
>> +#define __DT_BINDINGS_MAX77693_H
>> +
>> +/* External trigger type */
>> +#define MAX77693_LED_TRIG_TYPE_EDGE	0
>> +#define MAX77693_LED_TRIG_TYPE_LEVEL	1
>> +
>> +/* Boost modes */
>> +#define MAX77693_LED_BOOST_OFF		0
>> +#define MAX77693_LED_BOOST_ADAPTIVE	1
>> +#define MAX77693_LED_BOOST_FIXED	2
>> +
>> +#endif /* __DT_BINDINGS_MAX77693_H */
>
> These look fairly generic.  Do generic LED defines already exist?  If
> not, can they?

I am not entirely sure that they are generic. Different devices
may define different trigger types for low current LEDs and flash
LEDs. Boost modes could also have different semantics.

Regardless of the above we can consider renaming the file to
include/dt-bindings/leds/max77693.h

Bryan - what is your opinion?

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers
  2015-01-20 11:13       ` Lee Jones
@ 2015-01-20 12:57         ` Jacek Anaszewski
  -1 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-20 12:57 UTC (permalink / raw)
  To: Lee Jones
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ, pavel-+ZI9xUNit7I,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Chanwoo Choi

On 01/20/2015 12:13 PM, Lee Jones wrote:
> On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
>
>> Change flash cell identifiers from max77693-flash to max77693-led
>> to avoid confusion with NOR/NAND Flash.
>
> This is okay by me, but aren't these ABI yet?

No, the led driver using it hasn't been merged yet.

>> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Cc: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> ---
>>   drivers/mfd/max77693.c |    4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
>> index a159593..cb14afa 100644
>> --- a/drivers/mfd/max77693.c
>> +++ b/drivers/mfd/max77693.c
>> @@ -53,8 +53,8 @@ static const struct mfd_cell max77693_devs[] = {
>>   		.of_compatible = "maxim,max77693-haptic",
>>   	},
>>   	{
>> -		.name = "max77693-flash",
>> -		.of_compatible = "maxim,max77693-flash",
>> +		.name = "max77693-led",
>> +		.of_compatible = "maxim,max77693-led",
>>   	},
>>   };
>>
>


-- 
Best Regards,
Jacek Anaszewski
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers
@ 2015-01-20 12:57         ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-20 12:57 UTC (permalink / raw)
  To: Lee Jones
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On 01/20/2015 12:13 PM, Lee Jones wrote:
> On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
>
>> Change flash cell identifiers from max77693-flash to max77693-led
>> to avoid confusion with NOR/NAND Flash.
>
> This is okay by me, but aren't these ABI yet?

No, the led driver using it hasn't been merged yet.

>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> Cc: Chanwoo Choi <cw00.choi@samsung.com>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> ---
>>   drivers/mfd/max77693.c |    4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
>> index a159593..cb14afa 100644
>> --- a/drivers/mfd/max77693.c
>> +++ b/drivers/mfd/max77693.c
>> @@ -53,8 +53,8 @@ static const struct mfd_cell max77693_devs[] = {
>>   		.of_compatible = "maxim,max77693-haptic",
>>   	},
>>   	{
>> -		.name = "max77693-flash",
>> -		.of_compatible = "maxim,max77693-flash",
>> +		.name = "max77693-led",
>> +		.of_compatible = "maxim,max77693-led",
>>   	},
>>   };
>>
>


-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros
  2015-01-20 11:17   ` Lee Jones
@ 2015-01-20 13:01     ` Jacek Anaszewski
  2015-01-20 14:11       ` Jacek Anaszewski
  0 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-20 13:01 UTC (permalink / raw)
  To: Lee Jones
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On 01/20/2015 12:17 PM, Lee Jones wrote:
> On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
>
>> Modify FLASH_EN_SHIFT and TORCH_EN_SHIFT macros to work properly
>> when passed enum max77693_fled values (0 for FLED1 and 1 for FLED2)
>> from leds-max77693 driver.
>
> Off-by-one ay?  Wasn't the original code tested?

The driver using these macros is a part of LED / flash API integration
patch series, which still undergoes modifications and it hasn't
reached its final state yet, as there are many things to discuss.

>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> Cc: Chanwoo Choi <cw00.choi@samsung.com>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> ---
>>   include/linux/mfd/max77693-private.h |    4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
>> index 08dae01..01799a9 100644
>> --- a/include/linux/mfd/max77693-private.h
>> +++ b/include/linux/mfd/max77693-private.h
>> @@ -113,8 +113,8 @@ enum max77693_pmic_reg {
>>   #define FLASH_EN_FLASH		0x1
>>   #define FLASH_EN_TORCH		0x2
>>   #define FLASH_EN_ON		0x3
>> -#define FLASH_EN_SHIFT(x)	(6 - ((x) - 1) * 2)
>> -#define TORCH_EN_SHIFT(x)	(2 - ((x) - 1) * 2)
>> +#define FLASH_EN_SHIFT(x)	(6 - (x) * 2)
>> +#define TORCH_EN_SHIFT(x)	(2 - (x) * 2)
>>
>>   /* MAX77693 MAX_FLASH1 register */
>>   #define MAX_FLASH1_MAX_FL_EN	0x80
>


-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros
  2015-01-20 13:01     ` Jacek Anaszewski
@ 2015-01-20 14:11       ` Jacek Anaszewski
  2015-01-20 15:40         ` Lee Jones
  0 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-20 14:11 UTC (permalink / raw)
  To: Lee Jones
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On 01/20/2015 02:01 PM, Jacek Anaszewski wrote:
> On 01/20/2015 12:17 PM, Lee Jones wrote:
>> On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
>>
>>> Modify FLASH_EN_SHIFT and TORCH_EN_SHIFT macros to work properly
>>> when passed enum max77693_fled values (0 for FLED1 and 1 for FLED2)
>>> from leds-max77693 driver.
>>
>> Off-by-one ay?  Wasn't the original code tested?
>
> The driver using these macros is a part of LED / flash API integration
> patch series, which still undergoes modifications and it hasn't
> reached its final state yet, as there are many things to discuss.

To be more precise: the original code had been tested and was working
properly with the header that is in the mainline. Nonetheless, because
of the modifications in the driver that was requested during code
review, it turned out that it would be more convenient to redefine the
macros.

I'd opt for just agreeing about the mfd related patches and merge
them no sooner than the leds-max77693 driver is merged.

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693
  2015-01-20 11:21   ` Lee Jones
@ 2015-01-20 14:36     ` Jacek Anaszewski
       [not found]       ` <54BE67EA.2070507-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  0 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-20 14:36 UTC (permalink / raw)
  To: Lee Jones
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Andrzej Hajda, Chanwoo Choi, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala

On 01/20/2015 12:21 PM, Lee Jones wrote:
> On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
>
>> This patch adds device tree binding documentation for
>> the flash cell of the Maxim max77693 multifunctional device.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Cc: Chanwoo Choi <cw00.choi@samsung.com>
>> Cc: Bryan Wu <cooloney@gmail.com>
>> Cc: Richard Purdie <rpurdie@rpsys.net>
>> Cc: Rob Herring <robh+dt@kernel.org>
>> Cc: Pawel Moll <pawel.moll@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
>> Cc: Kumar Gala <galak@codeaurora.org>
>> ---
>>   Documentation/devicetree/bindings/mfd/max77693.txt |   69 ++++++++++++++++++++
>>   1 file changed, 69 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
>> index 01e9f30..ef184f0 100644
>> --- a/Documentation/devicetree/bindings/mfd/max77693.txt
>> +++ b/Documentation/devicetree/bindings/mfd/max77693.txt
>> @@ -41,7 +41,52 @@ Optional properties:
>>   	 To get more informations, please refer to documentaion.
>>   	[*] refer Documentation/devicetree/bindings/pwm/pwm.txt
>>
>> +- led : the LED submodule device node
>> +
>> +There are two led outputs available - fled1 and fled2. Each of them can
>> +control a separate led or they can be connected together to double
>> +the maximum current for a single connected led. One led is represented
>> +by one child node.
>> +
>> +Required properties:
>> +- compatible : Must be "maxim,max77693-led".
>> +
>> +Optional properties:
>> +- maxim,trigger-type : Flash trigger type.
>> +	Possible trigger types:
>> +		MAX77693_LED_TRIG_TYPE_EDGE - Rising edge of the signal triggers
>> +			the flash,
>> +		MAX77693_LED_TRIG_TYPE_LEVEL - Strobe pulse length controls
>> +			duration of the flash.
>
> I think you should represent the proper values here instead of the
> defines.

I see both versions in the existing bindings and also a combination of
them, e.g.: MAX77693_LED_TRIG_TYPE_EDGE (0). I think that it is
reasonable to mention the macros, especially if they are to appear
in the DT binding example at the end of the documentation file.

>> +- maxim,boost-mode :
>> +	In boost mode the device can produce up to 1.2A of total current
>> +	on both outputs. The maximum current on each output is reduced
>> +	to 625mA then. If not enabled explicitly, boost setting defaults to
>> +	MAX77693_LED_BOOST_FIXED in case both current sources are used.
>> +	Possible values:
>> +		MAX77693_LED_BOOST_OFF - no boost,
>> +		MAX77693_LED_BOOST_ADAPTIVE - adaptive mode,
>> +		MAX77693_LED_BOOST_FIXED - fixed mode.
>
> Same here.

MAX77693_LED_BOOST_OFF (0) - no boost,
MAX77693_LED_BOOST_ADAPTIVE (1) - adaptive mode,
MAX77693_LED_BOOST_FIXED (2) - fixed mode.

?

>
>> +- maxim,boost-vout : Output voltage of the boost module in millivolts.
>
> -mvout?
> -microvout?

maxim,boost-mvout ?

>> +- maxim,vsys-min : Low input voltage level in millivolts. Flash is not fired
>> +	if chip estimates that system voltage could drop below this level due
>> +	to flash power consumption.
>
> mvsys?
> microvsys?

maxim,mvsys-min ?

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693
  2015-01-20 14:36     ` Jacek Anaszewski
@ 2015-01-20 15:38           ` Lee Jones
  0 siblings, 0 replies; 107+ messages in thread
From: Lee Jones @ 2015-01-20 15:38 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ, pavel-+ZI9xUNit7I,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	sakari.ailus-X3B1VOXEql0, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	Andrzej Hajda, Chanwoo Choi, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala

On Tue, 20 Jan 2015, Jacek Anaszewski wrote:

> On 01/20/2015 12:21 PM, Lee Jones wrote:
> >On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
> >
> >>This patch adds device tree binding documentation for
> >>the flash cell of the Maxim max77693 multifunctional device.
> >>
> >>Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >>Signed-off-by: Andrzej Hajda <a.hajda-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >>Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >>Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> >>Cc: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >>Cc: Bryan Wu <cooloney-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> >>Cc: Richard Purdie <rpurdie-Fm38FmjxZ/leoWH0uzbU5w@public.gmane.org>
> >>Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> >>Cc: Pawel Moll <pawel.moll-5wv7dgnIgG8@public.gmane.org>
> >>Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> >>Cc: Ian Campbell <ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org>
> >>Cc: Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> >>---
> >>  Documentation/devicetree/bindings/mfd/max77693.txt |   69 ++++++++++++++++++++
> >>  1 file changed, 69 insertions(+)
> >>
> >>diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
> >>index 01e9f30..ef184f0 100644
> >>--- a/Documentation/devicetree/bindings/mfd/max77693.txt
> >>+++ b/Documentation/devicetree/bindings/mfd/max77693.txt
> >>@@ -41,7 +41,52 @@ Optional properties:
> >>  	 To get more informations, please refer to documentaion.
> >>  	[*] refer Documentation/devicetree/bindings/pwm/pwm.txt
> >>
> >>+- led : the LED submodule device node
> >>+
> >>+There are two led outputs available - fled1 and fled2. Each of them can
> >>+control a separate led or they can be connected together to double
> >>+the maximum current for a single connected led. One led is represented
> >>+by one child node.
> >>+
> >>+Required properties:
> >>+- compatible : Must be "maxim,max77693-led".
> >>+
> >>+Optional properties:
> >>+- maxim,trigger-type : Flash trigger type.
> >>+	Possible trigger types:
> >>+		MAX77693_LED_TRIG_TYPE_EDGE - Rising edge of the signal triggers
> >>+			the flash,
> >>+		MAX77693_LED_TRIG_TYPE_LEVEL - Strobe pulse length controls
> >>+			duration of the flash.
> >
> >I think you should represent the proper values here instead of the
> >defines.
> 
> I see both versions in the existing bindings and also a combination of
> them, e.g.: MAX77693_LED_TRIG_TYPE_EDGE (0). I think that it is
> reasonable to mention the macros, especially if they are to appear
> in the DT binding example at the end of the documentation file.
> 
> >>+- maxim,boost-mode :
> >>+	In boost mode the device can produce up to 1.2A of total current
> >>+	on both outputs. The maximum current on each output is reduced
> >>+	to 625mA then. If not enabled explicitly, boost setting defaults to
> >>+	MAX77693_LED_BOOST_FIXED in case both current sources are used.
> >>+	Possible values:
> >>+		MAX77693_LED_BOOST_OFF - no boost,
> >>+		MAX77693_LED_BOOST_ADAPTIVE - adaptive mode,
> >>+		MAX77693_LED_BOOST_FIXED - fixed mode.
> >
> >Same here.
> 
> MAX77693_LED_BOOST_OFF (0) - no boost,
> MAX77693_LED_BOOST_ADAPTIVE (1) - adaptive mode,
> MAX77693_LED_BOOST_FIXED (2) - fixed mode.

This is fine too.

> >>+- maxim,boost-vout : Output voltage of the boost module in millivolts.
> >
> >-mvout?
> >-microvout?
> 
> maxim,boost-mvout ?

Right.

> >>+- maxim,vsys-min : Low input voltage level in millivolts. Flash is not fired
> >>+	if chip estimates that system voltage could drop below this level due
> >>+	to flash power consumption.
> >
> >mvsys?
> >microvsys?
> 
> maxim,mvsys-min ?

Looks okay to me.

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693
@ 2015-01-20 15:38           ` Lee Jones
  0 siblings, 0 replies; 107+ messages in thread
From: Lee Jones @ 2015-01-20 15:38 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Andrzej Hajda, Chanwoo Choi, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala

On Tue, 20 Jan 2015, Jacek Anaszewski wrote:

> On 01/20/2015 12:21 PM, Lee Jones wrote:
> >On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
> >
> >>This patch adds device tree binding documentation for
> >>the flash cell of the Maxim max77693 multifunctional device.
> >>
> >>Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> >>Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> >>Cc: Lee Jones <lee.jones@linaro.org>
> >>Cc: Chanwoo Choi <cw00.choi@samsung.com>
> >>Cc: Bryan Wu <cooloney@gmail.com>
> >>Cc: Richard Purdie <rpurdie@rpsys.net>
> >>Cc: Rob Herring <robh+dt@kernel.org>
> >>Cc: Pawel Moll <pawel.moll@arm.com>
> >>Cc: Mark Rutland <mark.rutland@arm.com>
> >>Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> >>Cc: Kumar Gala <galak@codeaurora.org>
> >>---
> >>  Documentation/devicetree/bindings/mfd/max77693.txt |   69 ++++++++++++++++++++
> >>  1 file changed, 69 insertions(+)
> >>
> >>diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
> >>index 01e9f30..ef184f0 100644
> >>--- a/Documentation/devicetree/bindings/mfd/max77693.txt
> >>+++ b/Documentation/devicetree/bindings/mfd/max77693.txt
> >>@@ -41,7 +41,52 @@ Optional properties:
> >>  	 To get more informations, please refer to documentaion.
> >>  	[*] refer Documentation/devicetree/bindings/pwm/pwm.txt
> >>
> >>+- led : the LED submodule device node
> >>+
> >>+There are two led outputs available - fled1 and fled2. Each of them can
> >>+control a separate led or they can be connected together to double
> >>+the maximum current for a single connected led. One led is represented
> >>+by one child node.
> >>+
> >>+Required properties:
> >>+- compatible : Must be "maxim,max77693-led".
> >>+
> >>+Optional properties:
> >>+- maxim,trigger-type : Flash trigger type.
> >>+	Possible trigger types:
> >>+		MAX77693_LED_TRIG_TYPE_EDGE - Rising edge of the signal triggers
> >>+			the flash,
> >>+		MAX77693_LED_TRIG_TYPE_LEVEL - Strobe pulse length controls
> >>+			duration of the flash.
> >
> >I think you should represent the proper values here instead of the
> >defines.
> 
> I see both versions in the existing bindings and also a combination of
> them, e.g.: MAX77693_LED_TRIG_TYPE_EDGE (0). I think that it is
> reasonable to mention the macros, especially if they are to appear
> in the DT binding example at the end of the documentation file.
> 
> >>+- maxim,boost-mode :
> >>+	In boost mode the device can produce up to 1.2A of total current
> >>+	on both outputs. The maximum current on each output is reduced
> >>+	to 625mA then. If not enabled explicitly, boost setting defaults to
> >>+	MAX77693_LED_BOOST_FIXED in case both current sources are used.
> >>+	Possible values:
> >>+		MAX77693_LED_BOOST_OFF - no boost,
> >>+		MAX77693_LED_BOOST_ADAPTIVE - adaptive mode,
> >>+		MAX77693_LED_BOOST_FIXED - fixed mode.
> >
> >Same here.
> 
> MAX77693_LED_BOOST_OFF (0) - no boost,
> MAX77693_LED_BOOST_ADAPTIVE (1) - adaptive mode,
> MAX77693_LED_BOOST_FIXED (2) - fixed mode.

This is fine too.

> >>+- maxim,boost-vout : Output voltage of the boost module in millivolts.
> >
> >-mvout?
> >-microvout?
> 
> maxim,boost-mvout ?

Right.

> >>+- maxim,vsys-min : Low input voltage level in millivolts. Flash is not fired
> >>+	if chip estimates that system voltage could drop below this level due
> >>+	to flash power consumption.
> >
> >mvsys?
> >microvsys?
> 
> maxim,mvsys-min ?

Looks okay to me.

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros
  2015-01-20 14:11       ` Jacek Anaszewski
@ 2015-01-20 15:40         ` Lee Jones
  2015-01-20 16:00           ` Pavel Machek
  0 siblings, 1 reply; 107+ messages in thread
From: Lee Jones @ 2015-01-20 15:40 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On Tue, 20 Jan 2015, Jacek Anaszewski wrote:

> On 01/20/2015 02:01 PM, Jacek Anaszewski wrote:
> >On 01/20/2015 12:17 PM, Lee Jones wrote:
> >>On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
> >>
> >>>Modify FLASH_EN_SHIFT and TORCH_EN_SHIFT macros to work properly
> >>>when passed enum max77693_fled values (0 for FLED1 and 1 for FLED2)
> >>>from leds-max77693 driver.
> >>
> >>Off-by-one ay?  Wasn't the original code tested?
> >
> >The driver using these macros is a part of LED / flash API integration
> >patch series, which still undergoes modifications and it hasn't
> >reached its final state yet, as there are many things to discuss.
> 
> To be more precise: the original code had been tested and was working
> properly with the header that is in the mainline. Nonetheless, because
> of the modifications in the driver that was requested during code
> review, it turned out that it would be more convenient to redefine the
> macros.
> 
> I'd opt for just agreeing about the mfd related patches and merge
> them no sooner than the leds-max77693 driver is merged.

The only way we can guarantee this is to have them go in during
different merge-windows, unless of course they go in via the same tree.

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers
  2015-01-20 12:57         ` Jacek Anaszewski
  (?)
@ 2015-01-20 15:41         ` Lee Jones
  -1 siblings, 0 replies; 107+ messages in thread
From: Lee Jones @ 2015-01-20 15:41 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus, s.nawrocki,
	Chanwoo Choi

On Tue, 20 Jan 2015, Jacek Anaszewski wrote:

> On 01/20/2015 12:13 PM, Lee Jones wrote:
> >On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
> >
> >>Change flash cell identifiers from max77693-flash to max77693-led
> >>to avoid confusion with NOR/NAND Flash.
> >
> >This is okay by me, but aren't these ABI yet?
> 
> No, the led driver using it hasn't been merged yet.

Very well.

For my on reference:

Acked-by: Lee Jones <lee.jones@linaro.org>

> >>Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> >>Cc: Chanwoo Choi <cw00.choi@samsung.com>
> >>Cc: Lee Jones <lee.jones@linaro.org>
> >>---
> >>  drivers/mfd/max77693.c |    4 ++--
> >>  1 file changed, 2 insertions(+), 2 deletions(-)
> >>
> >>diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
> >>index a159593..cb14afa 100644
> >>--- a/drivers/mfd/max77693.c
> >>+++ b/drivers/mfd/max77693.c
> >>@@ -53,8 +53,8 @@ static const struct mfd_cell max77693_devs[] = {
> >>  		.of_compatible = "maxim,max77693-haptic",
> >>  	},
> >>  	{
> >>-		.name = "max77693-flash",
> >>-		.of_compatible = "maxim,max77693-flash",
> >>+		.name = "max77693-led",
> >>+		.of_compatible = "maxim,max77693-led",
> >>  	},
> >>  };
> >>
> >
> 
> 

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros
  2015-01-20 15:40         ` Lee Jones
@ 2015-01-20 16:00           ` Pavel Machek
  2015-01-20 16:41             ` Lee Jones
  0 siblings, 1 reply; 107+ messages in thread
From: Pavel Machek @ 2015-01-20 16:00 UTC (permalink / raw)
  To: Lee Jones
  Cc: Jacek Anaszewski, linux-leds, linux-media, linux-kernel,
	devicetree, kyungmin.park, b.zolnierkie, cooloney, rpurdie,
	sakari.ailus, s.nawrocki, Chanwoo Choi

On Tue 2015-01-20 15:40:29, Lee Jones wrote:
> On Tue, 20 Jan 2015, Jacek Anaszewski wrote:
> 
> > On 01/20/2015 02:01 PM, Jacek Anaszewski wrote:
> > >On 01/20/2015 12:17 PM, Lee Jones wrote:
> > >>On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
> > >>
> > >>>Modify FLASH_EN_SHIFT and TORCH_EN_SHIFT macros to work properly
> > >>>when passed enum max77693_fled values (0 for FLED1 and 1 for FLED2)
> > >>>from leds-max77693 driver.
> > >>
> > >>Off-by-one ay?  Wasn't the original code tested?
> > >
> > >The driver using these macros is a part of LED / flash API integration
> > >patch series, which still undergoes modifications and it hasn't
> > >reached its final state yet, as there are many things to discuss.
> > 
> > To be more precise: the original code had been tested and was working
> > properly with the header that is in the mainline. Nonetheless, because
> > of the modifications in the driver that was requested during code
> > review, it turned out that it would be more convenient to redefine the
> > macros.
> > 
> > I'd opt for just agreeing about the mfd related patches and merge
> > them no sooner than the leds-max77693 driver is merged.
> 
> The only way we can guarantee this is to have them go in during
> different merge-windows, unless of course they go in via the same tree.

Umm. Maintainers should be able to coordinate that. Delaying patch for
one major release seems rather cruel. Perhaps one maintainer should
ack the patch and the second one should merge it...
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-16 15:52                             ` Jacek Anaszewski
  (?)
@ 2015-01-20 16:09                             ` Jacek Anaszewski
  2015-01-20 17:29                               ` Rob Herring
  -1 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-20 16:09 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On 01/16/2015 04:52 PM, Jacek Anaszewski wrote:
> On 01/16/2015 02:48 PM, Rob Herring wrote:
>> On Fri, Jan 16, 2015 at 3:07 AM, Jacek Anaszewski
>> <j.anaszewski@samsung.com> wrote:
>>> On 01/15/2015 03:24 PM, Rob Herring wrote:
>>>>
>>>> On Tue, Jan 13, 2015 at 2:42 AM, Jacek Anaszewski
>>>> <j.anaszewski@samsung.com> wrote:
>>>>>
>>>>> On 01/12/2015 05:55 PM, Rob Herring wrote:
>>>>>>
>>>>>>
>>>>>> Adding Mark B and Liam...
>>>>>>
>>>>>> On Mon, Jan 12, 2015 at 10:10 AM, Jacek Anaszewski
>>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>>
>>>>>>>
>>>>>>> On 01/12/2015 02:52 PM, Rob Herring wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On Mon, Jan 12, 2015 at 2:32 AM, Jacek Anaszewski
>>>>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 01/09/2015 07:33 PM, Rob Herring wrote:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Fri, Jan 9, 2015 at 9:22 AM, Jacek Anaszewski
>>>>>>>>>> <j.anaszewski@samsung.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Add a property for defining the device outputs the LED
>>>>>>>>>>> represented by the DT child node is connected to.
>>>>>>
>>>>>>
>>>>>>
>>>>>> [...]
>>>>>>
>>>>>>>>>>> b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>>>> index a2c3f7a..29295bf 100644
>>>>>>>>>>> --- a/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>>>> +++ b/Documentation/devicetree/bindings/leds/common.txt
>>>>>>>>>>> @@ -1,6 +1,10 @@
>>>>>>>>>>>       Common leds properties.
>>>>>>>>>>>
>>>>>>>>>>>       Optional properties for child nodes:
>>>>>>>>>>> +- led-sources : Array of bits signifying the LED current
>>>>>>>>>>> regulator
>>>>>>>>>>> outputs the
>>>>>>>>>>> +               LED represented by the child node is
>>>>>>>>>>> connected to
>>>>>>>>>>> (1
>>>>>>>>>>> -
>>>>>>>>>>> the LED
>>>>>>>>>>> +               is connected to the output, 0 - the LED isn't
>>>>>>>>>>> connected
>>>>>>>>>>> to the
>>>>>>>>>>> +               output).
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Sorry, I just don't understand this.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> In some Flash LED devices one LED can be connected to one or more
>>>>>>>>> electric current outputs, which allows for multiplying the maximum
>>>>>>>>> current allowed for the LED. Each sub-LED is represented by a
>>>>>>>>> child
>>>>>>>>> node in the DT binding of the Flash LED device and it needs to
>>>>>>>>> declare
>>>>>>>>> which outputs it is connected to. In the example below the
>>>>>>>>> led-sources
>>>>>>>>> property is a two element array, which means that the flash LED
>>>>>>>>> device
>>>>>>>>> has two current outputs, and the bits signify if the LED is
>>>>>>>>> connected
>>>>>>>>> to the output.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Sounds like a regulator for which we already have bindings for
>>>>>>>> and we
>>>>>>>> have a driver for regulator based LEDs (but no binding for it).
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Do you think of drivers/leds/leds-regulator.c driver? This driver
>>>>>>> just
>>>>>>> allows for registering an arbitrary regulator device as a LED
>>>>>>> subsystem
>>>>>>> device.
>>>>>>>
>>>>>>> There are however devices that don't fall into this category,
>>>>>>> i.e. they
>>>>>>> have many outputs, that can be connected to a single LED or to many
>>>>>>> LEDs
>>>>>>> and the driver has to know what is the actual arrangement.
>>>>>>
>>>>>>
>>>>>>
>>>>>> We may need to extend the regulator binding slightly and allow for
>>>>>> multiple phandles on a supply property, but wouldn't something like
>>>>>> this work:
>>>>>>
>>>>>> led-supply = <&led-reg0>, <&led-reg1>, <&led-reg2>, <&led-reg3>;
>>>>>>
>>>>>> The shared source is already supported by the regulator binding.
>>>>>
>>>>>
>>>>>
>>>>> I think that we shouldn't split the LED devices into power supply
>>>>> providers and consumers as in case of generic regulators. From this
>>>>> point of view a LED device current output is a provider and a discrete
>>>>> LED element is a consumer. In this approach each discrete LED element
>>>>> should have a related driver which is not how LED devices are being
>>>>> handled in the LED subsystem, where there is a single binding for a
>>>>> LED
>>>>> device and there is a single driver for it which creates separate LED
>>>>> class devices for each LED connected to the LED device output. Each
>>>>> discrete LED is represented by a child node in the LED device binding.
>>>>>
>>>>> I am aware that it may be tempting to treat LED devices as common
>>>>> regulators, but they have their specific features which gave a
>>>>> reason for introducing LED class for them. Besides, there is already
>>>>> drivers/leds/leds-regulator.c driver for LED devices which support
>>>>> only
>>>>> turning on/off and setting brightness level.
>>>>>
>>>>> In your proposition a separate regulator provider binding would have
>>>>> to be created for each current output and a separate binding for
>>>>> each discrete LED connected to the LED device. It would create
>>>>> unnecessary noise in a dts file.
>>>>>
>>>>> Moreover, using regulator binding implies that we want to treat it
>>>>> as a sheer power supply for our device (which would be a discrete LED
>>>>> element in this case), whereas LED devices provide more features like
>>>>> blinking pattern and for flash LED devices - flash timeout, external
>>>>> strobe and flash faults.
>>>>
>>>>
>>>> Okay, fair enough. Please include some of this explanation in the
>>>> binding description.
>>>>
>>>> I do still have some concerns about led-sources and whether it can
>>>> support other scenarios. It is very much tied to the parent node. Are
>>>> there any cases where we don't want the LEDs to be sub nodes? Perhaps
>>>> the LEDs are on a separate daughterboard from the driver/supply and we
>>>> can have different drivers. It's a stretch maybe.
>>>
>>>
>>> I think it is. Such arrangements would introduce problems also to the
>>> other existing bindings. Probably not only LED subsystem related ones.
>>>
>>>> Or are there cases
>>>> where you need more information than just the connection?
>>>
>>>
>>> Currently I can't think of any.
>>>
>>> Modified rough proposal of the description:
>>>
>>>
>>> -Optional properties for child nodes:
>>> +LED and flash LED devices provide the same basic functionality as
>>> +current regulators, but extended with LED and flash LED specific
>>> +features
>>> like blinking patterns, flash timeout, flash faults and
>>> +external flash strobe mode.
>>> +
>>> +Many LED devices expose more than one current output that can be
>>> +connected to one or more discrete LED component. Since the arrangement
>>> +of connections can influence the way of the LED device initialization,
>>> +the LED components have to be tightly coupled with the LED device
>>> +binding. They are represented in the form of its child nodes.
>>> +
>>> +Optional properties for child nodes (if a LED device exposes only one
>>> +current output the properties can be placed directly in the LED device
>>> +node):
>>
>> Why special case 1 output case? Just always require a child node.
>
> OK.
>
>>> +- led-sources : Array of connection states between all LED current
>>> +               sources exposed by the device and this LED (1 - this LED
>>> +               is connected to the current output with index N, 0 -
>>> +               this LED isn't connected to the current output with
>>> +               index N); the mapping of N-th element of the array to
>>> +               the physical device output should be defined in the LED
>>> +               driver binding.
>>
>> I think this should be a list of connected output numbers rather than
>> effectively a bitmask.
>>
>> You may want to add something like led-output-cnt or led-driver-cnt in
>> the parent so you know the max list size.
>
> Why should we need this? The number of current outputs exposed by the
> device is fixed and can be specified in a LED device bindings
> documentation.
>

OK. The led-output-cnt property should be put in each sub-node, as the
number of the current outputs each LED can be connected to is variable.

New version:

  Optional properties for child nodes:
+led-sources-cnt : Number of device current outputs the LED is connected to.
+- led-sources : List of device current outputs the LED is connected to. The
+               outputs are identified by the numbers that must be defined
+               in the LED device binding documentation.
  - label : The label for this LED.  If omitted, the label is
    taken from the node name (excluding the unit address).

@@ -33,7 +47,9 @@ system-status {

  camera-flash {
         label = "Flash";
+       led-sources-cnt = <2>;
+       led-sources = <0>, <1>;
         max-microamp = <50000>;
         flash-max-microamp = <320000>;
         flash-timeout-us = <500000>;
-}
+};

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros
  2015-01-20 16:00           ` Pavel Machek
@ 2015-01-20 16:41             ` Lee Jones
  0 siblings, 0 replies; 107+ messages in thread
From: Lee Jones @ 2015-01-20 16:41 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Jacek Anaszewski, linux-leds, linux-media, linux-kernel,
	devicetree, kyungmin.park, b.zolnierkie, cooloney, rpurdie,
	sakari.ailus, s.nawrocki, Chanwoo Choi

On Tue, 20 Jan 2015, Pavel Machek wrote:
> On Tue 2015-01-20 15:40:29, Lee Jones wrote:
> > On Tue, 20 Jan 2015, Jacek Anaszewski wrote:
> > 
> > > On 01/20/2015 02:01 PM, Jacek Anaszewski wrote:
> > > >On 01/20/2015 12:17 PM, Lee Jones wrote:
> > > >>On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
> > > >>
> > > >>>Modify FLASH_EN_SHIFT and TORCH_EN_SHIFT macros to work properly
> > > >>>when passed enum max77693_fled values (0 for FLED1 and 1 for FLED2)
> > > >>>from leds-max77693 driver.
> > > >>
> > > >>Off-by-one ay?  Wasn't the original code tested?
> > > >
> > > >The driver using these macros is a part of LED / flash API integration
> > > >patch series, which still undergoes modifications and it hasn't
> > > >reached its final state yet, as there are many things to discuss.
> > > 
> > > To be more precise: the original code had been tested and was working
> > > properly with the header that is in the mainline. Nonetheless, because
> > > of the modifications in the driver that was requested during code
> > > review, it turned out that it would be more convenient to redefine the
> > > macros.
> > > 
> > > I'd opt for just agreeing about the mfd related patches and merge
> > > them no sooner than the leds-max77693 driver is merged.
> > 
> > The only way we can guarantee this is to have them go in during
> > different merge-windows, unless of course they go in via the same tree.
> 
> Umm. Maintainers should be able to coordinate that. Delaying patch for
> one major release seems rather cruel. Perhaps one maintainer should
> ack the patch and the second one should merge it...

Wow, you're just everywhere today. :)

Read the part after the comma again.

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-20 16:09                             ` Jacek Anaszewski
@ 2015-01-20 17:29                               ` Rob Herring
  2015-01-20 17:40                                 ` Pavel Machek
  0 siblings, 1 reply; 107+ messages in thread
From: Rob Herring @ 2015-01-20 17:29 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, Kyungmin Park,
	Bartlomiej Zolnierkiewicz, Pavel Machek, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On Tue, Jan 20, 2015 at 10:09 AM, Jacek Anaszewski
<j.anaszewski@samsung.com> wrote:
> On 01/16/2015 04:52 PM, Jacek Anaszewski wrote:
>>
>> On 01/16/2015 02:48 PM, Rob Herring wrote:

[...]

>>> You may want to add something like led-output-cnt or led-driver-cnt in
>>> the parent so you know the max list size.
>>
>>
>> Why should we need this? The number of current outputs exposed by the
>> device is fixed and can be specified in a LED device bindings
>> documentation.
>>
>
> OK. The led-output-cnt property should be put in each sub-node, as the
> number of the current outputs each LED can be connected to is variable.

Sorry, I meant this for the parent node meaning how many outputs the
driver IC has. I did say maybe because you may always know this. It
can make it easier to allocate memory for led-sources knowing the max
size up front.

Rob

>
> New version:
>
>  Optional properties for child nodes:
> +led-sources-cnt : Number of device current outputs the LED is connected to.
> +- led-sources : List of device current outputs the LED is connected to. The
> +               outputs are identified by the numbers that must be defined
> +               in the LED device binding documentation.
>  - label : The label for this LED.  If omitted, the label is
>    taken from the node name (excluding the unit address).
>
> @@ -33,7 +47,9 @@ system-status {
>
>  camera-flash {
>         label = "Flash";
> +       led-sources-cnt = <2>;
> +       led-sources = <0>, <1>;
>         max-microamp = <50000>;
>         flash-max-microamp = <320000>;
>         flash-timeout-us = <500000>;
> -}
> +};
>
>
> --
> Best Regards,
> Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-20 17:29                               ` Rob Herring
@ 2015-01-20 17:40                                 ` Pavel Machek
  2015-01-21  9:39                                   ` Jacek Anaszewski
  0 siblings, 1 reply; 107+ messages in thread
From: Pavel Machek @ 2015-01-20 17:40 UTC (permalink / raw)
  To: Rob Herring
  Cc: Jacek Anaszewski, linux-leds, linux-media, linux-kernel,
	devicetree, Kyungmin Park, Bartlomiej Zolnierkiewicz, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On Tue 2015-01-20 11:29:16, Rob Herring wrote:
> On Tue, Jan 20, 2015 at 10:09 AM, Jacek Anaszewski
> <j.anaszewski@samsung.com> wrote:
> > On 01/16/2015 04:52 PM, Jacek Anaszewski wrote:
> >>
> >> On 01/16/2015 02:48 PM, Rob Herring wrote:
> 
> [...]
> 
> >>> You may want to add something like led-output-cnt or led-driver-cnt in
> >>> the parent so you know the max list size.
> >>
> >>
> >> Why should we need this? The number of current outputs exposed by the
> >> device is fixed and can be specified in a LED device bindings
> >> documentation.
> >>
> >
> > OK. The led-output-cnt property should be put in each sub-node, as the
> > number of the current outputs each LED can be connected to is variable.
> 
> Sorry, I meant this for the parent node meaning how many outputs the
> driver IC has. I did say maybe because you may always know this. It
> can make it easier to allocate memory for led-sources knowing the max
> size up front.

Umm. Not sure if that kind of "help" should go to the device
tree.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-20 17:40                                 ` Pavel Machek
@ 2015-01-21  9:39                                   ` Jacek Anaszewski
  2015-01-28  7:04                                     ` Sakari Ailus
  0 siblings, 1 reply; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-21  9:39 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Rob Herring, linux-leds, linux-media, linux-kernel, devicetree,
	Kyungmin Park, Bartlomiej Zolnierkiewicz, Bryan Wu,
	Richard Purdie, sakari.ailus, Sylwester Nawrocki, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Liam Girdwood, Mark Brown

On 01/20/2015 06:40 PM, Pavel Machek wrote:
> On Tue 2015-01-20 11:29:16, Rob Herring wrote:
>> On Tue, Jan 20, 2015 at 10:09 AM, Jacek Anaszewski
>> <j.anaszewski@samsung.com> wrote:
>>> On 01/16/2015 04:52 PM, Jacek Anaszewski wrote:
>>>>
>>>> On 01/16/2015 02:48 PM, Rob Herring wrote:
>>
>> [...]
>>
>>>>> You may want to add something like led-output-cnt or led-driver-cnt in
>>>>> the parent so you know the max list size.
>>>>
>>>>
>>>> Why should we need this? The number of current outputs exposed by the
>>>> device is fixed and can be specified in a LED device bindings
>>>> documentation.
>>>>
>>>
>>> OK. The led-output-cnt property should be put in each sub-node, as the
>>> number of the current outputs each LED can be connected to is variable.
>>
>> Sorry, I meant this for the parent node meaning how many outputs the
>> driver IC has. I did say maybe because you may always know this. It
>> can make it easier to allocate memory for led-sources knowing the max
>> size up front.
>
> Umm. Not sure if that kind of "help" should go to the device
> tree.
> 									Pavel
>

I agree. I think that led-sources-cnt is redundant. A list property
can be read using of_prop_next_u32 function. I missed that and thus
proposed putting led-sources-cnt in each sub-node to be able to read 
led-sources list with of_property_read_u32_array.

Effectively, I propose to avoid adding led-sources-cnt property.

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 17/19] DT: Add documentation for exynos4-is 'flashes' property
  2015-01-09 15:23 ` [PATCH/RFC v10 17/19] DT: Add documentation for exynos4-is 'flashes' property Jacek Anaszewski
  2015-01-09 20:57   ` Pavel Machek
@ 2015-01-21 16:32   ` Sylwester Nawrocki
  2015-01-22  8:47     ` Jacek Anaszewski
  1 sibling, 1 reply; 107+ messages in thread
From: Sylwester Nawrocki @ 2015-01-21 16:32 UTC (permalink / raw)
  To: Jacek Anaszewski, linux-kernel
  Cc: linux-leds, linux-media, devicetree, kyungmin.park, b.zolnierkie,
	pavel, cooloney, rpurdie, sakari.ailus, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala

Hi,

On 09/01/15 16:23, Jacek Anaszewski wrote:
> This patch adds a description of 'flashes' property
> to the samsung-fimc.txt.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>

> ---
>  .../devicetree/bindings/media/samsung-fimc.txt     |    7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt
> index 922d6f8..22a6b2f 100644
> --- a/Documentation/devicetree/bindings/media/samsung-fimc.txt
> +++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt
> @@ -40,6 +40,12 @@ should be inactive. For the "active-a" state the camera port A must be activated
>  and the port B deactivated and for the state "active-b" it should be the other
>  way around.
>  
> +Optional properties:
> +
> +- flashes - Array of phandles to flash LED devices, or their sub-nodes
> +	    representing sub-leds.
> +	    (see Documentation/devicetree/bindings/leds/common.txt)

How about renaming this to "illuminators" or something else more generic?
The "torch" LED (for video recording illumination?) is not really a flash.

> +
>  The 'camera' node must include at least one 'fimc' child node.
>  
>  
> @@ -166,6 +172,7 @@ Example:
>  		clock-output-names = "cam_a_clkout", "cam_b_clkout";
>  		pinctrl-names = "default";
>  		pinctrl-0 = <&cam_port_a_clk_active>;
> +		flashes = <&camera_flash>, <&system_torch>;
>  		status = "okay";
>  		#address-cells = <1>;
>  		#size-cells = <1>;
--
Thanks,
Sylwester

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 17/19] DT: Add documentation for exynos4-is 'flashes' property
  2015-01-21 16:32   ` Sylwester Nawrocki
@ 2015-01-22  8:47     ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-01-22  8:47 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: linux-kernel, linux-leds, linux-media, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, sakari.ailus,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

Hi,

On 01/21/2015 05:32 PM, Sylwester Nawrocki wrote:
> Hi,
>
> On 09/01/15 16:23, Jacek Anaszewski wrote:
>> This patch adds a description of 'flashes' property
>> to the samsung-fimc.txt.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>
>> ---
>>   .../devicetree/bindings/media/samsung-fimc.txt     |    7 +++++++
>>   1 file changed, 7 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt
>> index 922d6f8..22a6b2f 100644
>> --- a/Documentation/devicetree/bindings/media/samsung-fimc.txt
>> +++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt
>> @@ -40,6 +40,12 @@ should be inactive. For the "active-a" state the camera port A must be activated
>>   and the port B deactivated and for the state "active-b" it should be the other
>>   way around.
>>
>> +Optional properties:
>> +
>> +- flashes - Array of phandles to flash LED devices, or their sub-nodes
>> +	    representing sub-leds.
>> +	    (see Documentation/devicetree/bindings/leds/common.txt)
>
> How about renaming this to "illuminators" or something else more generic?
> The "torch" LED (for video recording illumination?) is not really a flash.

OK, currently I can't think of a better substitute for 'illuminators'.

Since it has been agreed that a discrete LED component requires a child
node in a LED device binding, even if there is only one current output
exposed by the LED device, this description has to be modified as follows:

- illuminators - Array of phandles to the child nodes of a flash LED
	device related binding.
	(see Documentation/devicetree/bindings/leds/common.txt).


-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 01/19] leds: Add LED Flash class extension to the LED subsystem
  2015-01-09 17:37   ` Pavel Machek
@ 2015-01-26 23:02     ` Bryan Wu
  0 siblings, 0 replies; 107+ messages in thread
From: Bryan Wu @ 2015-01-26 23:02 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Jacek Anaszewski, Linux LED Subsystem, linux-media, lkml,
	devicetree, Kyungmin Park, b.zolnierkie, rpurdie, Sakari Ailus,
	Sylwester Nawrocki

On Fri, Jan 9, 2015 at 9:37 AM, Pavel Machek <pavel@ucw.cz> wrote:
> On Fri 2015-01-09 16:22:51, Jacek Anaszewski wrote:
>> Some LED devices support two operation modes - torch and flash.
>> This patch provides support for flash LED devices in the LED subsystem
>> by introducing new sysfs attributes and kernel internal interface.
>> The attributes being introduced are: flash_brightness, flash_strobe,
>> flash_timeout, max_flash_timeout, max_flash_brightness, flash_fault,
>> flash_sync_strobe and available_sync_leds. All the flash related
>> features are placed in a separate module.
>>
>> The modifications aim to be compatible with V4L2 framework requirements
>> related to the flash devices management. The design assumes that V4L2
>> sub-device can take of the LED class device control and communicate
>> with it through the kernel internal interface. When V4L2 Flash sub-device
>> file is opened, the LED class device sysfs interface is made
>> unavailable.
>>
>> 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>
>
> Acked-by: Pavel Machek <pavel@ucw.cz>
>

Applied to my tree. Thanks for pushing this.

-Bryan

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 02/19] Documentation: leds: Add description of LED Flash class extension
  2015-01-12  8:04     ` Jacek Anaszewski
@ 2015-01-26 23:03       ` Bryan Wu
  0 siblings, 0 replies; 107+ messages in thread
From: Bryan Wu @ 2015-01-26 23:03 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Pavel Machek, Linux LED Subsystem, linux-media, lkml, devicetree,
	Kyungmin Park, b.zolnierkie, rpurdie, Sakari Ailus,
	Sylwester Nawrocki

On Mon, Jan 12, 2015 at 12:04 AM, Jacek Anaszewski
<j.anaszewski@samsung.com> wrote:
> Hi Pavel,
>
> Thanks for the review.
>
> On 01/09/2015 06:40 PM, Pavel Machek wrote:
>>
>> Hi!
>>
>>> The documentation being added contains overall description of the
>>> LED Flash Class and the related sysfs attributes.
>>>
>>> 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>
>>
>>
>>> +In order to enable support for flash LEDs CONFIG_LEDS_CLASS_FLASH symbol
>>> +must be defined in the kernel config. A flash LED driver must register
>>> +in the LED subsystem with led_classdev_flash_register function to gain
>>> flash
>>> +related capabilities.
>>> +
>>> +There are flash LED devices which can control more than one LED and
>>> allow for
>>> +strobing the sub-leds synchronously. A LED will be strobed synchronously
>>> with
>>> +the one whose identifier is written to the flash_sync_strobe sysfs
>>> attribute.
>>> +The list of available sub-led identifiers can be read from the
>>
>>
>> sub-LED?
>
>
> Indeed, this naming will be more consistent.
>
>>> +       - flash_fault - bitmask of flash faults that may have occurred
>>> +                       possible flags are:
>>> +               * 0x01 - flash controller voltage to the flash LED has
>>> exceeded
>>> +                        the limit specific to the flash controller
>>> +               * 0x02 - the flash strobe was still on when the timeout
>>> set by
>>> +                        the user has expired; not all flash controllers
>>> may
>>> +                        set this in all such conditions
>>> +               * 0x04 - the flash controller has overheated
>>> +               * 0x08 - the short circuit protection of the flash
>>> controller
>>> +                        has been triggered
>>> +               * 0x10 - current in the LED power supply has exceeded the
>>> limit
>>> +                        specific to the flash controller
>>> +               * 0x20 - the flash controller has detected a short or
>>> open
>>> +                        circuit condition on the indicator LED
>>> +               * 0x40 - flash controller voltage to the flash LED has
>>> been
>>> +                        below the minimum limit specific to the flash
>>> +               * 0x80 - the input voltage of the flash controller is
>>> below
>>> +                        the limit under which strobing the flash at full
>>> +                        current will not be possible. The condition
>>> persists
>>> +                        until this flag is no longer set
>>> +               * 0x100 - the temperature of the LED has exceeded its
>>> allowed
>>> +                         upper limit
>>
>>
>> Did not everyone agree that text strings are preferable to bitmasks?
>>
>>
>> Pavel
>>
>
> I just forgot to update the flash_fault documentation. Will fix in the
> next version.
>
Please provide an updated version. I will merge them.

-Bryan

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 03/19] DT: leds: Add led-sources property
  2015-01-21  9:39                                   ` Jacek Anaszewski
@ 2015-01-28  7:04                                     ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2015-01-28  7:04 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Pavel Machek, Rob Herring, linux-leds, linux-media, linux-kernel,
	devicetree, Kyungmin Park, Bartlomiej Zolnierkiewicz, Bryan Wu,
	Richard Purdie, Sylwester Nawrocki, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Liam Girdwood,
	Mark Brown

On Wed, Jan 21, 2015 at 10:39:05AM +0100, Jacek Anaszewski wrote:
> I agree. I think that led-sources-cnt is redundant. A list property
> can be read using of_prop_next_u32 function. I missed that and thus
> proposed putting led-sources-cnt in each sub-node to be able to read
> led-sources list with of_property_read_u32_array.
> 
> Effectively, I propose to avoid adding led-sources-cnt property.

You can also read the array size using of_get_property().

-- 
Regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros
  2015-01-20 12:53     ` Jacek Anaszewski
@ 2015-01-28  8:52       ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2015-01-28  8:52 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: Lee Jones, linux-leds, linux-media, linux-kernel, devicetree,
	kyungmin.park, b.zolnierkie, pavel, cooloney, rpurdie,
	s.nawrocki, Chanwoo Choi

Hi Jacek,

On Tue, Jan 20, 2015 at 01:53:05PM +0100, Jacek Anaszewski wrote:
> On 01/20/2015 12:12 PM, Lee Jones wrote:
> >On Fri, 09 Jan 2015, Jacek Anaszewski wrote:
> >
> >>Add macros for max77693 led part related binding.
> >>
> >>Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> >>Cc: Lee Jones <lee.jones@linaro.org>
> >>Cc: Chanwoo Choi <cw00.choi@samsung.com>
> >>---
> >>  include/dt-bindings/mfd/max77693.h |   21 +++++++++++++++++++++
> >>  1 file changed, 21 insertions(+)
> >>  create mode 100644 include/dt-bindings/mfd/max77693.h
> >>
> >>diff --git a/include/dt-bindings/mfd/max77693.h b/include/dt-bindings/mfd/max77693.h
> >>new file mode 100644
> >>index 0000000..f53e197
> >>--- /dev/null
> >>+++ b/include/dt-bindings/mfd/max77693.h
> >>@@ -0,0 +1,21 @@
> >>+/*
> >>+ * This header provides macros for MAX77693 device binding
> >>+ *
> >>+ * Copyright (C) 2014, Samsung Electronics Co., Ltd.
> >>+ *
> >>+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
> >>+ */
> >>+
> >>+#ifndef __DT_BINDINGS_MAX77693_H__
> >>+#define __DT_BINDINGS_MAX77693_H
> >>+
> >>+/* External trigger type */
> >>+#define MAX77693_LED_TRIG_TYPE_EDGE	0
> >>+#define MAX77693_LED_TRIG_TYPE_LEVEL	1
> >>+
> >>+/* Boost modes */
> >>+#define MAX77693_LED_BOOST_OFF		0
> >>+#define MAX77693_LED_BOOST_ADAPTIVE	1
> >>+#define MAX77693_LED_BOOST_FIXED	2
> >>+
> >>+#endif /* __DT_BINDINGS_MAX77693_H */
> >
> >These look fairly generic.  Do generic LED defines already exist?  If
> >not, can they?
> 
> I am not entirely sure that they are generic. Different devices
> may define different trigger types for low current LEDs and flash
> LEDs. Boost modes could also have different semantics.
> 
> Regardless of the above we can consider renaming the file to
> include/dt-bindings/leds/max77693.h
> 
> Bryan - what is your opinion?

At least trigger type can be chosen for lm3555 (as3645a) as well. I'm not
sure about boost mode.

-- 
Regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell
  2015-01-09 15:22 ` [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell Jacek Anaszewski
@ 2015-02-05 15:34       ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2015-02-05 15:34 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	b.zolnierkie-Sze3O3UU22JBDgjK7y7TUQ, pavel-+ZI9xUNit7I,
	cooloney-Re5JQEeQqe8AvxtiuMwx3w, rpurdie-Fm38FmjxZ/leoWH0uzbU5w,
	s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ, Andrzej Hajda, Lee Jones,
	Chanwoo Choi

Hi Jacek,

A few comments below.

On Fri, Jan 09, 2015 at 04:22:58PM +0100, Jacek Anaszewski wrote:
> This patch adds led-flash support to Maxim max77693 chipset.
> A device can be exposed to user space through LED subsystem
> sysfs interface. Device supports up to two leds which can
> work in flash and torch mode. The leds can be triggered
> externally or by software.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Andrzej Hajda <a.hajda-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Bryan Wu <cooloney-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Cc: Richard Purdie <rpurdie-Fm38FmjxZ/leoWH0uzbU5w@public.gmane.org>
> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Cc: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/leds/Kconfig         |   10 +
>  drivers/leds/Makefile        |    1 +
>  drivers/leds/leds-max77693.c | 1045 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1056 insertions(+)
>  create mode 100644 drivers/leds/leds-max77693.c
> 
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 95029df..ff9c21b 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -464,6 +464,16 @@ config LEDS_TCA6507
>  	  LED driver chips accessed via the I2C bus.
>  	  Driver support brightness control and hardware-assisted blinking.
>  
> +config LEDS_MAX77693
> +	tristate "LED support for MAX77693 Flash"
> +	depends on LEDS_CLASS_FLASH
> +	depends on MFD_MAX77693
> +	depends on OF
> +	help
> +	  This option enables support for the flash part of the MAX77693
> +	  multifunction device. It has build in control for two leds in flash
> +	  and torch mode.
> +
>  config LEDS_MAX8997
>  	tristate "LED support for MAX8997 PMIC"
>  	depends on LEDS_CLASS && MFD_MAX8997
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index cbba921..57ca62b 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -52,6 +52,7 @@ obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
>  obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
>  obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
>  obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
> +obj-$(CONFIG_LEDS_MAX77693)		+= leds-max77693.o
>  obj-$(CONFIG_LEDS_MAX8997)		+= leds-max8997.o
>  obj-$(CONFIG_LEDS_LM355x)		+= leds-lm355x.o
>  obj-$(CONFIG_LEDS_BLINKM)		+= leds-blinkm.o
> diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
> new file mode 100644
> index 0000000..3ba07c4
> --- /dev/null
> +++ b/drivers/leds/leds-max77693.c
> @@ -0,0 +1,1045 @@
> +/*
> + * LED Flash class driver for the flash cell of max77693 mfd.
> + *
> + *	Copyright (C) 2015, Samsung Electronics Co., Ltd.
> + *
> + *	Authors: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + *		 Andrzej Hajda <a.hajda-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + */
> +
> +#include <asm/div64.h>
> +#include <linux/led-class-flash.h>
> +#include <linux/mfd/max77693.h>
> +#include <linux/mfd/max77693-private.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +
> +#define MODE_OFF		0
> +#define MODE_FLASH(a)		(1 << (a))
> +#define MODE_TORCH(a)		(1 << (2 + (a)))
> +#define MODE_FLASH_EXTERNAL(a)	(1 << (4 + (a)))
> +
> +#define MODE_FLASH_MASK		(MODE_FLASH(FLED1) | MODE_FLASH(FLED2) | \
> +				 MODE_FLASH_EXTERNAL(FLED1) | \
> +				 MODE_FLASH_EXTERNAL(FLED2))
> +#define MODE_TORCH_MASK		(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))
> +
> +#define FLED1_IOUT		(1 << 0)
> +#define FLED2_IOUT		(1 << 1)
> +
> +enum max77693_fled {
> +	FLED1,
> +	FLED2,
> +};
> +
> +enum max77693_led_mode {
> +	FLASH,
> +	TORCH,
> +};
> +
> +struct max77693_sub_led {
> +	/* related FLED output identifier */
> +	int fled_id;
> +	/* related LED Flash class device */
> +	struct led_classdev_flash fled_cdev;
> +	/* assures led-triggers compatibility */
> +	struct work_struct work_brightness_set;
> +
> +	/* brightness cache */
> +	unsigned int torch_brightness;
> +	/* flash timeout cache */
> +	unsigned int flash_timeout;
> +};
> +
> +struct max77693_led_device {
> +	/* parent mfd regmap */
> +	struct regmap *regmap;
> +	/* platform device data */
> +	struct platform_device *pdev;
> +	/* configuration data for the device */
> +	struct max77693_led_config_data *cfg_data;

Where is this defined?

> +	/* secures access to the device */
> +	struct mutex lock;
> +
> +	/* sub led data */
> +	struct max77693_sub_led sub_leds[2];
> +
> +	/* current flash timeout cache */
> +	unsigned int current_flash_timeout;
> +	/* ITORCH register cache */
> +	u8 torch_iout_reg;
> +	/* mode of fled outputs */
> +	unsigned int mode_flags;
> +	/* recently strobed fled */
> +	int strobing_sub_led_id;
> +	/* bitmask of fled outputs use state (bit 0. - FLED1, bit 1. - FLED2) */
> +	u8 fled_mask;
> +	/* fled modes that can be set */
> +	u8 allowed_modes;
> +
> +	/* arrangement of current outputs */
> +	bool iout_joint;
> +};
> +
> +struct max77693_led_settings {
> +	struct led_flash_setting torch_brightness;
> +	struct led_flash_setting flash_brightness;
> +	struct led_flash_setting flash_timeout;
> +};
> +
> +static u8 max77693_led_iout_to_reg(u32 ua)
> +{
> +	if (ua < FLASH_IOUT_MIN)
> +		ua = FLASH_IOUT_MIN;
> +	return (ua - FLASH_IOUT_MIN) / FLASH_IOUT_STEP;
> +}
> +
> +static u8 max77693_flash_timeout_to_reg(u32 us)
> +{
> +	return (us - FLASH_TIMEOUT_MIN) / FLASH_TIMEOUT_STEP;
> +}
> +
> +static inline struct max77693_sub_led *flcdev_to_sub_led(
> +					struct led_classdev_flash *fled_cdev)
> +{
> +	return container_of(fled_cdev, struct max77693_sub_led, fled_cdev);
> +}
> +
> +static inline struct max77693_led_device *sub_led_to_led(
> +					struct max77693_sub_led *sub_led)
> +{
> +	return container_of(sub_led, struct max77693_led_device,
> +				sub_leds[sub_led->fled_id]);
> +}
> +
> +static inline u8 max77693_led_vsys_to_reg(u32 mv)
> +{
> +	return ((mv - MAX_FLASH1_VSYS_MIN) / MAX_FLASH1_VSYS_STEP) << 2;
> +}
> +
> +static inline u8 max77693_led_vout_to_reg(u32 mv)
> +{
> +	return (mv - FLASH_VOUT_MIN) / FLASH_VOUT_STEP + FLASH_VOUT_RMIN;
> +}
> +
> +static inline bool max77693_fled_used(struct max77693_led_device *led,
> +					 int fled_id)
> +{
> +	u8 fled_bit = (fled_id == FLED1) ? FLED1_IOUT : FLED2_IOUT;
> +
> +	return led->fled_mask & fled_bit;
> +}
> +
> +/* split composite current @i into two @iout according to @imax weights */

Do you still consider this as the right thing to do?

If there's a single LED driven by multiple outputs, what is the value
provided by board-specific current distribution between these outputs?

> +static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
> +{
> +	u64 t = i;
> +
> +	t *= imax[1];
> +	do_div(t, imax[0] + imax[1]);
> +
> +	iout[1] = (u32)t / FLASH_IOUT_STEP * FLASH_IOUT_STEP;
> +	iout[0] = i - iout[1];
> +}
> +
> +static int max77693_set_mode(struct max77693_led_device *led, u8 mode)
> +{
> +	struct regmap *rmap = led->regmap;
> +	int ret, v = 0, i;
> +
> +	for (i = FLED1; i <= FLED2; ++i) {
> +		if (mode & MODE_TORCH(i))
> +			v |= FLASH_EN_ON << TORCH_EN_SHIFT(i);
> +
> +		if (mode & MODE_FLASH(i)) {
> +			v |= FLASH_EN_ON << FLASH_EN_SHIFT(i);
> +		} else if (mode & MODE_FLASH_EXTERNAL(i)) {
> +			v |= FLASH_EN_FLASH << FLASH_EN_SHIFT(i);
> +			/*
> +			 * Enable hw triggering also for torch mode, as some
> +			 * camera sensors use torch led to fathom ambient light
> +			 * conditions before strobing the flash.
> +			 */
> +			v |= FLASH_EN_TORCH << TORCH_EN_SHIFT(i);
> +		}
> +	}
> +
> +	/* Reset the register only prior setting flash modes */
> +	if (mode & ~(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))) {
> +		ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, 0);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, v);
> +}
> +
> +static void max77693_set_sync_strobe(struct max77693_led_device *led,
> +					u8 *mode)
> +{
> +	struct max77693_sub_led *sub_leds = led->sub_leds;
> +	struct led_classdev_flash *fled_cdev;
> +	u8 m = *mode;
> +
> +	if (led->iout_joint)
> +		return;
> +
> +	/* Check if the other sub-led wants to be strobed simultaneously. */
> +	if (m & (MODE_FLASH(FLED1) | MODE_FLASH_EXTERNAL(FLED1))) {
> +		fled_cdev = &sub_leds[FLED2].fled_cdev;
> +		if (fled_cdev->sync_led_id)
> +			m |= m << 1;
> +	} else if (m & (MODE_FLASH(FLED2) | MODE_FLASH_EXTERNAL(FLED2))) {
> +		fled_cdev = &sub_leds[FLED1].fled_cdev;
> +		if (fled_cdev->sync_led_id)
> +			m |= m >> 1;
> +	}
> +
> +	*mode = m;
> +}
> +
> +static int max77693_add_mode(struct max77693_led_device *led, u8 mode)
> +{
> +	int i, ret;
> +
> +	mode &= led->allowed_modes;
> +
> +	/*
> +	 * Torch mode once enabled remains active until turned off. If the FLED2
> +	 * output isn't to be disabled check if the torch mode to be set isn't
> +	 * already activated and avoid re-setting it.
> +	 */
> +	if ((!(mode ^ led->mode_flags)) & MODE_TORCH(FLED2)) {
> +		for (i = FLED1; i <= FLED2; ++i)
> +			if ((mode & MODE_TORCH(i)) &&
> +			    (led->mode_flags & MODE_TORCH(i)))
> +				return 0;
> +	}
> +
> +	/* Span the mode on FLED2 for joint iouts case */
> +	if (led->iout_joint)
> +		mode |= (mode << 1);
> +
> +	/* Span the flash mode on the other led if it is to be synchronized */
> +	max77693_set_sync_strobe(led, &mode);
> +
> +	/*
> +	 * FLASH_EXTERNAL mode activates FLASHEN and TORCHEN pins in the device.
> +	 * The related register bits fields interfere with SW triggerred modes,
> +	 * thus clear them to ensure proper device configuration.
> +	 */
> +	for (i = FLED1; i <= FLED2; ++i)
> +		if (mode & MODE_FLASH_EXTERNAL(i))
> +			led->mode_flags &= (~MODE_TORCH(i) & ~MODE_FLASH(i));
> +
> +	led->mode_flags |= mode;
> +	led->mode_flags &= led->allowed_modes;
> +
> +	ret = max77693_set_mode(led, led->mode_flags);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * Clear flash mode flag after setting the mode to avoid spurious flash
> +	 * strobing on each subsequent torch mode setting.
> +	 */
> +	if (mode & MODE_FLASH_MASK)
> +		led->mode_flags &= ~mode;
> +
> +	return ret;
> +}
> +
> +static int max77693_clear_mode(struct max77693_led_device *led,
> +				u8 mode)
> +{
> +	int ret;
> +
> +	if (led->iout_joint)
> +		/* Clear mode also on FLED2 for joint iouts case */
> +		mode |= (mode << 1);
> +	else
> +		/*
> +		 * Clear a flash mode on the other led
> +		 * if it is to be synchronized.
> +		 */
> +		max77693_set_sync_strobe(led, &mode);
> +
> +	led->mode_flags &= ~mode;
> +
> +	ret = max77693_set_mode(led, led->mode_flags);
> +
> +	return ret;
> +}
> +
> +static void max77693_calc_iout(struct max77693_led_device *led, int fled_id,
> +				u32 iout[2], u32 micro_amp, u32 iout_max[2],
> +				enum max77693_led_mode mode)
> +{
> +	u8 blocked_modes;
> +
> +	if (fled_id == FLED1) {
> +		if (led->iout_joint) {
> +			/*
> +			 * FLED2 must not be turned on to get
> +			 * 15625 uA of total current.
> +			 */
> +			if (micro_amp == FLASH_IOUT_MIN) {
> +				if (mode == FLASH)
> +					blocked_modes =
> +						MODE_FLASH(FLED2) |
> +						MODE_FLASH_EXTERNAL(FLED2);
> +				else
> +					blocked_modes = MODE_TORCH(FLED2);
> +
> +				led->allowed_modes &= ~blocked_modes;
> +			}
> +		} else {
> +			/*
> +			 * Preclude splitting current to FLED2 if we
> +			 * are driving two separate leds.
> +			 */
> +			iout_max[FLED2] = 0;
> +		}
> +		__max77693_calc_iout(iout, micro_amp, iout_max);
> +	} else if (fled_id == FLED2) {
> +		/*
> +		 * Preclude splitting current to FLED1 if we
> +		 * are driving two separate leds.
> +		 */
> +		iout_max[FLED1] = 0;
> +		__max77693_calc_iout(iout, micro_amp, iout_max);
> +	}
> +}
> +
> +static int max77693_set_torch_current(struct max77693_led_device *led,
> +				int fled_id, u32 micro_amp)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct regmap *rmap = led->regmap;
> +	u32 iout[2], iout_max[2];
> +	u8 iout1_reg = 0, iout2_reg = 0;
> +
> +	iout_max[FLED1] = cfg->iout_torch[FLED1];
> +	iout_max[FLED2] = cfg->iout_torch[FLED2];
> +
> +	led->allowed_modes |= MODE_TORCH_MASK;
> +
> +	max77693_calc_iout(led, fled_id, iout, micro_amp, iout_max,

Could you use cfg->iout_torch directly?

> +				TORCH);
> +
> +	if (fled_id == FLED1 || led->iout_joint) {
> +		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);
> +		led->torch_iout_reg &= 0xf0;

I think it'd be cleaner to use register bit names and led-specific shift
here. Up to you.

> +	}
> +	if (fled_id == FLED2 || led->iout_joint) {
> +		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);
> +		led->torch_iout_reg &= 0x0f;
> +	}
> +
> +	led->torch_iout_reg |= ((iout1_reg << TORCH_IOUT1_SHIFT) |
> +				(iout2_reg << TORCH_IOUT2_SHIFT));
> +
> +	return regmap_write(rmap, MAX77693_LED_REG_ITORCH,
> +						led->torch_iout_reg);
> +}
> +
> +static int max77693_set_flash_current(struct max77693_led_device *led,
> +					int fled_id,
> +					u32 micro_amp)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct regmap *rmap = led->regmap;
> +	u32 iout[2], iout_max[2];
> +	u8 iout1_reg, iout2_reg;
> +	int ret = -EINVAL;
> +
> +	iout_max[FLED1] = cfg->iout_flash[FLED1];
> +	iout_max[FLED2] = cfg->iout_flash[FLED2];
> +
> +	led->allowed_modes |= MODE_FLASH_MASK;
> +
> +	max77693_calc_iout(led, fled_id, iout, micro_amp, iout_max,
> +				FLASH);
> +
> +	if (fled_id == FLED1 || led->iout_joint) {
> +		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);
> +		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH1,
> +							iout1_reg);
> +		if (ret < 0)
> +			return ret;
> +	}
> +	if (fled_id == FLED2 || led->iout_joint) {
> +		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);
> +		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH2,
> +							iout2_reg);
> +	}
> +
> +	return ret;
> +}
> +
> +static int max77693_set_timeout(struct max77693_led_device *led, u32 microsec)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct regmap *rmap = led->regmap;
> +	u8 v;
> +	int ret;
> +
> +	v = max77693_flash_timeout_to_reg(microsec);
> +
> +	if (cfg->trigger_type == MAX77693_LED_TRIG_TYPE_LEVEL)
> +		v |= FLASH_TMR_LEVEL;
> +
> +	ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_TIMER, v);
> +	if (ret < 0)
> +		return ret;
> +
> +	led->current_flash_timeout = microsec;
> +
> +	return 0;
> +}
> +
> +static int max77693_strobe_status_get(struct max77693_led_device *led,
> +					bool *state)
> +{
> +	struct regmap *rmap = led->regmap;
> +	unsigned int v;
> +	int ret;
> +
> +	ret = regmap_read(rmap, MAX77693_LED_REG_FLASH_STATUS, &v);
> +	if (ret < 0)
> +		return ret;
> +
> +	*state = v & FLASH_STATUS_FLASH_ON;
> +
> +	return ret;
> +}
> +
> +static int max77693_int_flag_get(struct max77693_led_device *led,
> +					unsigned int *v)
> +{
> +	struct regmap *rmap = led->regmap;
> +
> +	return regmap_read(rmap, MAX77693_LED_REG_FLASH_INT, v);
> +}
> +
> +static int max77693_setup(struct max77693_led_device *led)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct regmap *rmap = led->regmap;
> +	int i, first_led, last_led, ret;
> +	u32 max_flash_curr[2];
> +	u8 v;
> +
> +	/*
> +	 * Initialize only flash current. Torch current doesn't
> +	 * require initialization as ITORCH register is written with
> +	 * new value each time brightness_set op is called.
> +	 */
> +	if (led->iout_joint) {
> +		first_led = FLED1;
> +		last_led = FLED1;
> +		max_flash_curr[FLED1] = cfg->iout_flash[FLED1] +
> +					cfg->iout_flash[FLED2];
> +	} else {
> +		first_led = max77693_fled_used(led, FLED1) ? FLED1 : FLED2;
> +		last_led = led->cfg_data->num_leds == 2 ? FLED2 : first_led;
> +		max_flash_curr[FLED1] = cfg->iout_flash[FLED1];
> +		max_flash_curr[FLED2] = cfg->iout_flash[FLED2];
> +	}
> +
> +	for (i = first_led; i <= last_led; ++i) {
> +		ret = max77693_set_flash_current(led, i,
> +					max_flash_curr[i]);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	v = TORCH_TMR_NO_TIMER | MAX77693_LED_TRIG_TYPE_LEVEL;
> +	ret = regmap_write(rmap, MAX77693_LED_REG_ITORCHTIMER, v);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* initially set FLED1 timeout */
> +	ret = max77693_set_timeout(led, cfg->flash_timeout[FLED1]);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (cfg->low_vsys > 0)
> +		v = max77693_led_vsys_to_reg(cfg->low_vsys) |
> +						MAX_FLASH1_MAX_FL_EN;
> +	else
> +		v = 0;
> +
> +	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH1, v);
> +	if (ret < 0)
> +		return ret;
> +	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH2, 0);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (cfg->boost_mode == MAX77693_LED_BOOST_FIXED)
> +		v = FLASH_BOOST_FIXED;
> +	else
> +		v = cfg->boost_mode | cfg->boost_mode << 1;
> +
> +	if (max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))
> +		v |= FLASH_BOOST_LEDNUM_2;
> +
> +	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_CNTL, v);
> +	if (ret < 0)
> +		return ret;
> +
> +	v = max77693_led_vout_to_reg(cfg->boost_vout);
> +	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_FLASH1, v);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Allow all modes on both fled outputs */
> +	led->allowed_modes = MODE_FLASH_MASK | MODE_TORCH_MASK;
> +
> +	return max77693_set_mode(led, MODE_OFF);
> +}
> +
> +static int __max77693_led_brightness_set(struct max77693_led_device *led,
> +					int fled_id, enum led_brightness value)
> +{
> +	int ret;
> +
> +	mutex_lock(&led->lock);
> +
> +	if (value == 0) {
> +		ret = max77693_clear_mode(led, MODE_TORCH(fled_id));
> +		if (ret < 0)
> +			dev_dbg(&led->pdev->dev,
> +				"Failed to clear torch mode (%d)\n",
> +				ret);
> +		goto unlock;
> +	}
> +
> +	ret = max77693_set_torch_current(led, fled_id, value * TORCH_IOUT_STEP);
> +	if (ret < 0) {
> +		dev_dbg(&led->pdev->dev,
> +			"Failed to set torch current (%d)\n",
> +			ret);
> +		goto unlock;
> +	}
> +
> +	ret = max77693_add_mode(led, MODE_TORCH(fled_id));
> +	if (ret < 0)
> +		dev_dbg(&led->pdev->dev,
> +			"Failed to set torch mode (%d)\n",
> +			ret);
> +unlock:
> +	mutex_unlock(&led->lock);
> +	return ret;
> +}
> +
> +static void max77693_led_brightness_set_work(
> +					struct work_struct *work)
> +{
> +	struct max77693_sub_led *sub_led =
> +			container_of(work, struct max77693_sub_led,
> +					work_brightness_set);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +
> +	__max77693_led_brightness_set(led, sub_led->fled_id,
> +				sub_led->torch_brightness);
> +}
> +
> +/* LED subsystem callbacks */
> +
> +static int max77693_led_brightness_set_sync(
> +				struct led_classdev *led_cdev,
> +				enum led_brightness value)
> +{
> +	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +
> +	return __max77693_led_brightness_set(led, sub_led->fled_id, value);
> +}
> +
> +static void max77693_led_brightness_set(
> +				struct led_classdev *led_cdev,
> +				enum led_brightness value)
> +{
> +	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +
> +	sub_led->torch_brightness = value;
> +	schedule_work(&sub_led->work_brightness_set);
> +}
> +
> +static int max77693_led_flash_brightness_set(
> +				struct led_classdev_flash *fled_cdev,
> +				u32 brightness)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +	int ret;
> +
> +	mutex_lock(&led->lock);
> +	ret = max77693_set_flash_current(led, sub_led->fled_id, brightness);
> +	mutex_unlock(&led->lock);
> +
> +	return ret;
> +}
> +
> +static int max77693_led_flash_strobe_set(
> +				struct led_classdev_flash *fled_cdev,
> +				bool state)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(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 (!state) {
> +		ret = max77693_clear_mode(led, MODE_FLASH(fled_id));
> +		goto unlock;
> +	}
> +
> +	if (sub_led->flash_timeout != led->current_flash_timeout) {
> +		ret = max77693_set_timeout(led, sub_led->flash_timeout);
> +		if (ret < 0)
> +			goto unlock;
> +	}
> +
> +	led->strobing_sub_led_id = fled_id;
> +
> +	ret = max77693_add_mode(led, MODE_FLASH(fled_id));
> +
> +unlock:
> +	mutex_unlock(&led->lock);
> +	return ret;
> +}
> +
> +static int max77693_led_flash_fault_get(
> +				struct led_classdev_flash *fled_cdev,
> +				u32 *fault)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +	unsigned int v;
> +	int ret;
> +
> +	ret = max77693_int_flag_get(led, &v);
> +	if (ret < 0)
> +		return ret;
> +
> +	*fault = 0;
> +
> +	if (v & ((sub_led->fled_id == FLED1) ? FLASH_INT_FLED1_OPEN :
> +					       FLASH_INT_FLED2_OPEN))
> +		*fault |= LED_FAULT_OVER_VOLTAGE;
> +	if (v & ((sub_led->fled_id == FLED1) ? FLASH_INT_FLED1_SHORT :
> +					       FLASH_INT_FLED2_SHORT))
> +		*fault |= LED_FAULT_SHORT_CIRCUIT;
> +	if (v & FLASH_INT_OVER_CURRENT)
> +		*fault |= LED_FAULT_OVER_CURRENT;
> +
> +	return 0;
> +}
> +
> +static int max77693_led_flash_strobe_get(
> +				struct led_classdev_flash *fled_cdev,
> +				bool *state)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +	int ret;
> +
> +	if (!state)
> +		return -EINVAL;
> +
> +	mutex_lock(&led->lock);
> +
> +	ret = max77693_strobe_status_get(led, state);
> +
> +	*state = !!(*state && (led->strobing_sub_led_id == sub_led->fled_id));
> +
> +
> +	mutex_unlock(&led->lock);
> +
> +	return ret;
> +}
> +
> +static int max77693_led_flash_timeout_set(
> +				struct led_classdev_flash *fled_cdev,
> +				u32 timeout)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +
> +	mutex_lock(&led->lock);
> +	sub_led->flash_timeout = timeout;
> +	mutex_unlock(&led->lock);
> +
> +	return 0;
> +}
> +
> +static int max77693_led_parse_dt(struct max77693_led_device *led,
> +				 struct device_node *node)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct max77693_sub_led *sub_leds = led->sub_leds;
> +	struct device *dev = &led->pdev->dev;
> +	struct device_node *child_node;
> +	u32 led_sources[2];
> +	int fled_id, ret;
> +
> +	of_property_read_u32(node, "maxim,trigger-type", &cfg->trigger_type);
> +	of_property_read_u32(node, "maxim,boost-mode", &cfg->boost_mode);
> +	of_property_read_u32(node, "maxim,boost-vout", &cfg->boost_vout);
> +	of_property_read_u32(node, "maxim,vsys-min", &cfg->low_vsys);
> +
> +	for_each_available_child_of_node(node, child_node) {
> +		ret = of_property_read_u32_array(child_node, "led-sources",
> +							led_sources, 2);
> +		if (ret < 0) {
> +			dev_err(dev,
> +				"Error reading \"led-sources\" DT property\n");
> +			return ret;
> +		}
> +
> +		if (led_sources[0] && led_sources[1]) {
> +			fled_id = FLED1;
> +			led->fled_mask = FLED1_IOUT | FLED2_IOUT;
> +		} else if (led_sources[0] && !led_sources[1]) {
> +			fled_id = FLED1;
> +			led->fled_mask |= FLED1_IOUT;
> +		} else if (!led_sources[0] && led_sources[1]) {
> +			fled_id = FLED2;
> +			led->fled_mask |= FLED2_IOUT;
> +		} else {
> +			dev_err(dev,
> +				"Wrong \"led-sources\" DT property value\n");
> +			return -EINVAL;
> +		}
> +
> +		sub_leds[fled_id].fled_id = fled_id;
> +
> +		ret = of_property_read_string(child_node, "label",
> +					(const char **) &cfg->label[fled_id]);
> +		if (ret < 0) {
> +			dev_err(dev, "Error reading \"label\" DT property\n");
> +			return ret;
> +		}
> +
> +		of_property_read_u32(child_node, "max-microamp",
> +						&cfg->iout_torch[fled_id]);
> +		of_property_read_u32(child_node, "flash-max-microamp",
> +						&cfg->iout_flash[fled_id]);
> +		of_property_read_u32(child_node, "flash-timeout-us",
> +						&cfg->flash_timeout[fled_id]);
> +
> +		if (++led->cfg_data->num_leds == 2 ||
> +		    (max77693_fled_used(led, FLED1) &&
> +		     max77693_fled_used(led, FLED2)))
> +			break;
> +	}
> +
> +	return 0;
> +}
> +
> +static void clamp_align(u32 *v, u32 min, u32 max, u32 step)
> +{
> +	*v = clamp_val(*v, min, max);
> +	if (step > 1)
> +		*v = (*v - min) / step * step + min;
> +}
> +
> +static void max77693_led_validate_configuration(struct max77693_led_device *led)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	int i;
> +
> +	if (led->cfg_data->num_leds == 1 &&
> +	    max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))
> +		led->iout_joint = true;
> +
> +	cfg->boost_mode = clamp_val(cfg->boost_mode, MAX77693_LED_BOOST_NONE,
> +			    MAX77693_LED_BOOST_FIXED);
> +
> +	/* Boost must be enabled if both current outputs are used */
> +	if ((cfg->boost_mode == MAX77693_LED_BOOST_NONE) && led->iout_joint)
> +		cfg->boost_mode = MAX77693_LED_BOOST_FIXED;
> +
> +	/* Split max current settings to both outputs in case of joint leds */
> +	if (led->iout_joint) {
> +		cfg->iout_torch[FLED1] /= 2;
> +		cfg->iout_torch[FLED2] = cfg->iout_torch[FLED1];
> +		cfg->iout_flash[FLED1] /= 2;
> +		cfg->iout_flash[FLED2] = cfg->iout_flash[FLED1];
> +	}
> +
> +	for (i = FLED1; i <= FLED2; ++i) {
> +		if (max77693_fled_used(led, i)) {
> +			clamp_align(&cfg->iout_torch[i], TORCH_IOUT_MIN,
> +					TORCH_IOUT_MAX, TORCH_IOUT_STEP);
> +			clamp_align(&cfg->iout_flash[i], FLASH_IOUT_MIN,
> +					cfg->boost_mode ? FLASH_IOUT_MAX_2LEDS :
> +							FLASH_IOUT_MAX_1LED,
> +					FLASH_IOUT_STEP);
> +		} else {
> +			cfg->iout_torch[i] = cfg->iout_flash[i] = 0;
> +		}
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(cfg->flash_timeout); ++i)
> +		clamp_align(&cfg->flash_timeout[i], FLASH_TIMEOUT_MIN,
> +				FLASH_TIMEOUT_MAX, FLASH_TIMEOUT_STEP);
> +
> +	cfg->trigger_type = clamp_val(cfg->trigger_type,
> +					MAX77693_LED_TRIG_TYPE_EDGE,
> +					MAX77693_LED_TRIG_TYPE_LEVEL);
> +
> +	clamp_align(&cfg->boost_vout, FLASH_VOUT_MIN, FLASH_VOUT_MAX,
> +							FLASH_VOUT_STEP);
> +
> +	if (cfg->low_vsys)
> +		clamp_align(&cfg->low_vsys, MAX_FLASH1_VSYS_MIN,
> +				MAX_FLASH1_VSYS_MAX, MAX_FLASH1_VSYS_STEP);
> +}
> +
> +static int max77693_led_get_configuration(struct max77693_led_device *led)
> +{
> +	struct device *dev = &led->pdev->dev;
> +	int ret;
> +
> +	if (!dev->of_node)
> +		return -EINVAL;
> +
> +	led->cfg_data = devm_kzalloc(dev, sizeof(*led->cfg_data), GFP_KERNEL);
> +	if (!led->cfg_data)
> +		return -ENOMEM;
> +
> +	ret = max77693_led_parse_dt(led, dev->of_node);
> +	if (ret < 0)
> +		return ret;
> +
> +	max77693_led_validate_configuration(led);
> +
> +	return 0;
> +}
> +
> +static const struct led_flash_ops flash_ops = {
> +	.flash_brightness_set	= max77693_led_flash_brightness_set,
> +	.strobe_set		= max77693_led_flash_strobe_set,
> +	.strobe_get		= max77693_led_flash_strobe_get,
> +	.timeout_set		= max77693_led_flash_timeout_set,
> +	.fault_get		= max77693_led_flash_fault_get,
> +};
> +
> +static void max77693_init_flash_settings(struct max77693_led_device *led,
> +					 struct max77693_led_settings *s,
> +					 int fled_id)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct led_flash_setting *setting;
> +
> +	/* Init torch intensity setting */
> +	setting = &s->torch_brightness;
> +	setting->min = TORCH_IOUT_MIN;
> +	setting->max = cfg->iout_torch[fled_id];
> +	setting->max = led->iout_joint ?
> +			cfg->iout_torch[FLED1] + cfg->iout_torch[FLED2] :
> +			cfg->iout_torch[fled_id];
> +	setting->step = TORCH_IOUT_STEP;
> +	setting->val = setting->max;
> +
> +	/* Init flash intensity setting */
> +	setting = &s->flash_brightness;
> +	setting->min = FLASH_IOUT_MIN;
> +	setting->max = led->iout_joint ?
> +			cfg->iout_flash[FLED1] + cfg->iout_flash[FLED2] :
> +			cfg->iout_flash[fled_id];
> +	setting->step = FLASH_IOUT_STEP;
> +	setting->val = setting->max;
> +
> +	/* Init flash timeout setting */
> +	setting = &s->flash_timeout;
> +	setting->min = FLASH_TIMEOUT_MIN;
> +	setting->max = cfg->flash_timeout[fled_id];
> +	setting->step = FLASH_TIMEOUT_STEP;
> +	setting->val = setting->max;
> +}
> +
> +static int max77693_set_available_sync_led(struct max77693_led_device *led,
> +						int fled_id)
> +{
> +	struct max77693_sub_led *sub_led = &led->sub_leds[fled_id];
> +	struct led_classdev_flash *fled_cdev = &sub_led->fled_cdev;
> +
> +	fled_cdev->sync_leds = devm_kzalloc(&led->pdev->dev, sizeof(fled_cdev),
> +					GFP_KERNEL);
> +	if (!fled_cdev->sync_leds)
> +		return -ENOMEM;
> +
> +	fled_cdev->sync_leds[0] = &led->sub_leds[!fled_id].fled_cdev;
> +	fled_cdev->num_sync_leds = 1;
> +
> +	return 0;
> +}
> +
> +static void max77693_init_fled_cdev(struct max77693_led_device *led,
> +					int fled_id)
> +{
> +	struct led_classdev_flash *fled_cdev;
> +	struct led_classdev *led_cdev;
> +	struct max77693_sub_led *sub_led = &led->sub_leds[fled_id];
> +	struct max77693_led_settings settings;
> +
> +	/* Initialize flash settings */
> +	max77693_init_flash_settings(led, &settings, fled_id);
> +
> +	/* Initialize LED Flash class device */
> +	fled_cdev = &sub_led->fled_cdev;
> +	fled_cdev->ops = &flash_ops;
> +	led_cdev = &fled_cdev->led_cdev;
> +	led_cdev->name = led->cfg_data->label[fled_id];
> +	led_cdev->brightness_set = max77693_led_brightness_set;
> +	led_cdev->brightness_set_sync = max77693_led_brightness_set_sync;
> +	INIT_WORK(&sub_led->work_brightness_set,
> +			max77693_led_brightness_set_work);
> +
> +	led_cdev->max_brightness = settings.torch_brightness.val /
> +					TORCH_IOUT_STEP;
> +	led_cdev->flags |= LED_DEV_CAP_FLASH;
> +	if (led->cfg_data->num_leds == 2)
> +		led_cdev->flags |= LED_DEV_CAP_SYNC_STROBE;
> +
> +	fled_cdev->brightness = settings.flash_brightness;
> +	fled_cdev->timeout = settings.flash_timeout;
> +	sub_led->flash_timeout = fled_cdev->timeout.val;
> +}
> +
> +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;
> +	int init_fled_cdev[2], i, ret;
> +
> +	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
> +	if (!led)
> +		return -ENOMEM;
> +
> +	led->pdev = pdev;
> +	led->regmap = iodev->regmap;
> +	sub_leds = led->sub_leds;
> +
> +	platform_set_drvdata(pdev, led);
> +	ret = max77693_led_get_configuration(led);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = max77693_setup(led);
> +	if (ret < 0)
> +		return ret;
> +
> +	init_fled_cdev[FLED1] =
> +			led->iout_joint || max77693_fled_used(led, FLED1);
> +	init_fled_cdev[FLED2] =
> +			!led->iout_joint && max77693_fled_used(led, FLED2);
> +
> +	/* Initialize LED Flash class device(s) */
> +	for (i = FLED1; i <= FLED2; ++i)
> +		if (init_fled_cdev[i])
> +			max77693_init_fled_cdev(led, i);
> +
> +	/* Setup sub-leds available for flash strobe synchronization */
> +	if (led->cfg_data->num_leds == 2) {
> +		for (i = FLED1; i <= FLED2; ++i) {
> +			ret = max77693_set_available_sync_led(led, i);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
> +	mutex_init(&led->lock);
> +
> +	/* Register LED Flash class device(s) */
> +	for (i = FLED1; i <= FLED2; ++i) {
> +		if (init_fled_cdev[i]) {

if (!...)
	continue;

The rest of the loop would look nicer this way I think. Up to you.

> +			ret = led_classdev_flash_register(dev,
> +							&sub_leds[i].fled_cdev);
> +			if (ret < 0) {
> +				/*
> +				 * At this moment FLED1 might have been already
> +				 * registered and it needs to be released.
> +				 */
> +				if (i == FLED2)
> +					goto err_register_led2;
> +				else
> +					goto err_register_led1;
> +			}
> +		}
> +	}
> +
> +
> +	return 0;
> +
> +err_register_led2:
> +	/* It is possible than only FLED2 was to be registered */
> +	if (!init_fled_cdev[FLED1])
> +		goto err_register_led1;
> +	led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
> +err_register_led1:
> +	mutex_destroy(&led->lock);
> +
> +	return ret;
> +}
> +
> +static int max77693_led_remove(struct platform_device *pdev)
> +{
> +	struct max77693_led_device *led = platform_get_drvdata(pdev);
> +	struct max77693_sub_led *sub_leds = led->sub_leds;
> +
> +	if (led->iout_joint || max77693_fled_used(led, FLED1)) {
> +		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)) {
> +		led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);
> +		cancel_work_sync(&sub_leds[FLED2].work_brightness_set);
> +	}
> +
> +	mutex_destroy(&led->lock);
> +
> +	return 0;
> +}
> +
> +static struct of_device_id max77693_led_dt_match[] = {
> +	{.compatible = "maxim,max77693-led"},
> +	{},
> +};
> +
> +static struct platform_driver max77693_led_driver = {
> +	.probe		= max77693_led_probe,
> +	.remove		= max77693_led_remove,
> +	.driver		= {
> +		.name	= "max77693-led",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = max77693_led_dt_match,
> +	},
> +};
> +
> +module_platform_driver(max77693_led_driver);
> +
> +MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
> +MODULE_AUTHOR("Andrzej Hajda <a.hajda-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
> +MODULE_DESCRIPTION("Maxim MAX77693 led flash driver");
> +MODULE_LICENSE("GPL v2");

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus-X3B1VOXEql0@public.gmane.org	XMPP: sailus-PCDdDYkjdNMDXYZnReoRVg@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell
@ 2015-02-05 15:34       ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2015-02-05 15:34 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, s.nawrocki,
	Andrzej Hajda, Lee Jones, Chanwoo Choi

Hi Jacek,

A few comments below.

On Fri, Jan 09, 2015 at 04:22:58PM +0100, Jacek Anaszewski wrote:
> This patch adds led-flash support to Maxim max77693 chipset.
> A device can be exposed to user space through LED subsystem
> sysfs interface. Device supports up to two leds which can
> work in flash and torch mode. The leds can be triggered
> externally or by software.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Bryan Wu <cooloney@gmail.com>
> Cc: Richard Purdie <rpurdie@rpsys.net>
> Cc: Lee Jones <lee.jones@linaro.org>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  drivers/leds/Kconfig         |   10 +
>  drivers/leds/Makefile        |    1 +
>  drivers/leds/leds-max77693.c | 1045 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1056 insertions(+)
>  create mode 100644 drivers/leds/leds-max77693.c
> 
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 95029df..ff9c21b 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -464,6 +464,16 @@ config LEDS_TCA6507
>  	  LED driver chips accessed via the I2C bus.
>  	  Driver support brightness control and hardware-assisted blinking.
>  
> +config LEDS_MAX77693
> +	tristate "LED support for MAX77693 Flash"
> +	depends on LEDS_CLASS_FLASH
> +	depends on MFD_MAX77693
> +	depends on OF
> +	help
> +	  This option enables support for the flash part of the MAX77693
> +	  multifunction device. It has build in control for two leds in flash
> +	  and torch mode.
> +
>  config LEDS_MAX8997
>  	tristate "LED support for MAX8997 PMIC"
>  	depends on LEDS_CLASS && MFD_MAX8997
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index cbba921..57ca62b 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -52,6 +52,7 @@ obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
>  obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
>  obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
>  obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
> +obj-$(CONFIG_LEDS_MAX77693)		+= leds-max77693.o
>  obj-$(CONFIG_LEDS_MAX8997)		+= leds-max8997.o
>  obj-$(CONFIG_LEDS_LM355x)		+= leds-lm355x.o
>  obj-$(CONFIG_LEDS_BLINKM)		+= leds-blinkm.o
> diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
> new file mode 100644
> index 0000000..3ba07c4
> --- /dev/null
> +++ b/drivers/leds/leds-max77693.c
> @@ -0,0 +1,1045 @@
> +/*
> + * LED Flash class driver for the flash cell of max77693 mfd.
> + *
> + *	Copyright (C) 2015, Samsung Electronics Co., Ltd.
> + *
> + *	Authors: Jacek Anaszewski <j.anaszewski@samsung.com>
> + *		 Andrzej Hajda <a.hajda@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + */
> +
> +#include <asm/div64.h>
> +#include <linux/led-class-flash.h>
> +#include <linux/mfd/max77693.h>
> +#include <linux/mfd/max77693-private.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +
> +#define MODE_OFF		0
> +#define MODE_FLASH(a)		(1 << (a))
> +#define MODE_TORCH(a)		(1 << (2 + (a)))
> +#define MODE_FLASH_EXTERNAL(a)	(1 << (4 + (a)))
> +
> +#define MODE_FLASH_MASK		(MODE_FLASH(FLED1) | MODE_FLASH(FLED2) | \
> +				 MODE_FLASH_EXTERNAL(FLED1) | \
> +				 MODE_FLASH_EXTERNAL(FLED2))
> +#define MODE_TORCH_MASK		(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))
> +
> +#define FLED1_IOUT		(1 << 0)
> +#define FLED2_IOUT		(1 << 1)
> +
> +enum max77693_fled {
> +	FLED1,
> +	FLED2,
> +};
> +
> +enum max77693_led_mode {
> +	FLASH,
> +	TORCH,
> +};
> +
> +struct max77693_sub_led {
> +	/* related FLED output identifier */
> +	int fled_id;
> +	/* related LED Flash class device */
> +	struct led_classdev_flash fled_cdev;
> +	/* assures led-triggers compatibility */
> +	struct work_struct work_brightness_set;
> +
> +	/* brightness cache */
> +	unsigned int torch_brightness;
> +	/* flash timeout cache */
> +	unsigned int flash_timeout;
> +};
> +
> +struct max77693_led_device {
> +	/* parent mfd regmap */
> +	struct regmap *regmap;
> +	/* platform device data */
> +	struct platform_device *pdev;
> +	/* configuration data for the device */
> +	struct max77693_led_config_data *cfg_data;

Where is this defined?

> +	/* secures access to the device */
> +	struct mutex lock;
> +
> +	/* sub led data */
> +	struct max77693_sub_led sub_leds[2];
> +
> +	/* current flash timeout cache */
> +	unsigned int current_flash_timeout;
> +	/* ITORCH register cache */
> +	u8 torch_iout_reg;
> +	/* mode of fled outputs */
> +	unsigned int mode_flags;
> +	/* recently strobed fled */
> +	int strobing_sub_led_id;
> +	/* bitmask of fled outputs use state (bit 0. - FLED1, bit 1. - FLED2) */
> +	u8 fled_mask;
> +	/* fled modes that can be set */
> +	u8 allowed_modes;
> +
> +	/* arrangement of current outputs */
> +	bool iout_joint;
> +};
> +
> +struct max77693_led_settings {
> +	struct led_flash_setting torch_brightness;
> +	struct led_flash_setting flash_brightness;
> +	struct led_flash_setting flash_timeout;
> +};
> +
> +static u8 max77693_led_iout_to_reg(u32 ua)
> +{
> +	if (ua < FLASH_IOUT_MIN)
> +		ua = FLASH_IOUT_MIN;
> +	return (ua - FLASH_IOUT_MIN) / FLASH_IOUT_STEP;
> +}
> +
> +static u8 max77693_flash_timeout_to_reg(u32 us)
> +{
> +	return (us - FLASH_TIMEOUT_MIN) / FLASH_TIMEOUT_STEP;
> +}
> +
> +static inline struct max77693_sub_led *flcdev_to_sub_led(
> +					struct led_classdev_flash *fled_cdev)
> +{
> +	return container_of(fled_cdev, struct max77693_sub_led, fled_cdev);
> +}
> +
> +static inline struct max77693_led_device *sub_led_to_led(
> +					struct max77693_sub_led *sub_led)
> +{
> +	return container_of(sub_led, struct max77693_led_device,
> +				sub_leds[sub_led->fled_id]);
> +}
> +
> +static inline u8 max77693_led_vsys_to_reg(u32 mv)
> +{
> +	return ((mv - MAX_FLASH1_VSYS_MIN) / MAX_FLASH1_VSYS_STEP) << 2;
> +}
> +
> +static inline u8 max77693_led_vout_to_reg(u32 mv)
> +{
> +	return (mv - FLASH_VOUT_MIN) / FLASH_VOUT_STEP + FLASH_VOUT_RMIN;
> +}
> +
> +static inline bool max77693_fled_used(struct max77693_led_device *led,
> +					 int fled_id)
> +{
> +	u8 fled_bit = (fled_id == FLED1) ? FLED1_IOUT : FLED2_IOUT;
> +
> +	return led->fled_mask & fled_bit;
> +}
> +
> +/* split composite current @i into two @iout according to @imax weights */

Do you still consider this as the right thing to do?

If there's a single LED driven by multiple outputs, what is the value
provided by board-specific current distribution between these outputs?

> +static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
> +{
> +	u64 t = i;
> +
> +	t *= imax[1];
> +	do_div(t, imax[0] + imax[1]);
> +
> +	iout[1] = (u32)t / FLASH_IOUT_STEP * FLASH_IOUT_STEP;
> +	iout[0] = i - iout[1];
> +}
> +
> +static int max77693_set_mode(struct max77693_led_device *led, u8 mode)
> +{
> +	struct regmap *rmap = led->regmap;
> +	int ret, v = 0, i;
> +
> +	for (i = FLED1; i <= FLED2; ++i) {
> +		if (mode & MODE_TORCH(i))
> +			v |= FLASH_EN_ON << TORCH_EN_SHIFT(i);
> +
> +		if (mode & MODE_FLASH(i)) {
> +			v |= FLASH_EN_ON << FLASH_EN_SHIFT(i);
> +		} else if (mode & MODE_FLASH_EXTERNAL(i)) {
> +			v |= FLASH_EN_FLASH << FLASH_EN_SHIFT(i);
> +			/*
> +			 * Enable hw triggering also for torch mode, as some
> +			 * camera sensors use torch led to fathom ambient light
> +			 * conditions before strobing the flash.
> +			 */
> +			v |= FLASH_EN_TORCH << TORCH_EN_SHIFT(i);
> +		}
> +	}
> +
> +	/* Reset the register only prior setting flash modes */
> +	if (mode & ~(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))) {
> +		ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, 0);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, v);
> +}
> +
> +static void max77693_set_sync_strobe(struct max77693_led_device *led,
> +					u8 *mode)
> +{
> +	struct max77693_sub_led *sub_leds = led->sub_leds;
> +	struct led_classdev_flash *fled_cdev;
> +	u8 m = *mode;
> +
> +	if (led->iout_joint)
> +		return;
> +
> +	/* Check if the other sub-led wants to be strobed simultaneously. */
> +	if (m & (MODE_FLASH(FLED1) | MODE_FLASH_EXTERNAL(FLED1))) {
> +		fled_cdev = &sub_leds[FLED2].fled_cdev;
> +		if (fled_cdev->sync_led_id)
> +			m |= m << 1;
> +	} else if (m & (MODE_FLASH(FLED2) | MODE_FLASH_EXTERNAL(FLED2))) {
> +		fled_cdev = &sub_leds[FLED1].fled_cdev;
> +		if (fled_cdev->sync_led_id)
> +			m |= m >> 1;
> +	}
> +
> +	*mode = m;
> +}
> +
> +static int max77693_add_mode(struct max77693_led_device *led, u8 mode)
> +{
> +	int i, ret;
> +
> +	mode &= led->allowed_modes;
> +
> +	/*
> +	 * Torch mode once enabled remains active until turned off. If the FLED2
> +	 * output isn't to be disabled check if the torch mode to be set isn't
> +	 * already activated and avoid re-setting it.
> +	 */
> +	if ((!(mode ^ led->mode_flags)) & MODE_TORCH(FLED2)) {
> +		for (i = FLED1; i <= FLED2; ++i)
> +			if ((mode & MODE_TORCH(i)) &&
> +			    (led->mode_flags & MODE_TORCH(i)))
> +				return 0;
> +	}
> +
> +	/* Span the mode on FLED2 for joint iouts case */
> +	if (led->iout_joint)
> +		mode |= (mode << 1);
> +
> +	/* Span the flash mode on the other led if it is to be synchronized */
> +	max77693_set_sync_strobe(led, &mode);
> +
> +	/*
> +	 * FLASH_EXTERNAL mode activates FLASHEN and TORCHEN pins in the device.
> +	 * The related register bits fields interfere with SW triggerred modes,
> +	 * thus clear them to ensure proper device configuration.
> +	 */
> +	for (i = FLED1; i <= FLED2; ++i)
> +		if (mode & MODE_FLASH_EXTERNAL(i))
> +			led->mode_flags &= (~MODE_TORCH(i) & ~MODE_FLASH(i));
> +
> +	led->mode_flags |= mode;
> +	led->mode_flags &= led->allowed_modes;
> +
> +	ret = max77693_set_mode(led, led->mode_flags);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * Clear flash mode flag after setting the mode to avoid spurious flash
> +	 * strobing on each subsequent torch mode setting.
> +	 */
> +	if (mode & MODE_FLASH_MASK)
> +		led->mode_flags &= ~mode;
> +
> +	return ret;
> +}
> +
> +static int max77693_clear_mode(struct max77693_led_device *led,
> +				u8 mode)
> +{
> +	int ret;
> +
> +	if (led->iout_joint)
> +		/* Clear mode also on FLED2 for joint iouts case */
> +		mode |= (mode << 1);
> +	else
> +		/*
> +		 * Clear a flash mode on the other led
> +		 * if it is to be synchronized.
> +		 */
> +		max77693_set_sync_strobe(led, &mode);
> +
> +	led->mode_flags &= ~mode;
> +
> +	ret = max77693_set_mode(led, led->mode_flags);
> +
> +	return ret;
> +}
> +
> +static void max77693_calc_iout(struct max77693_led_device *led, int fled_id,
> +				u32 iout[2], u32 micro_amp, u32 iout_max[2],
> +				enum max77693_led_mode mode)
> +{
> +	u8 blocked_modes;
> +
> +	if (fled_id == FLED1) {
> +		if (led->iout_joint) {
> +			/*
> +			 * FLED2 must not be turned on to get
> +			 * 15625 uA of total current.
> +			 */
> +			if (micro_amp == FLASH_IOUT_MIN) {
> +				if (mode == FLASH)
> +					blocked_modes =
> +						MODE_FLASH(FLED2) |
> +						MODE_FLASH_EXTERNAL(FLED2);
> +				else
> +					blocked_modes = MODE_TORCH(FLED2);
> +
> +				led->allowed_modes &= ~blocked_modes;
> +			}
> +		} else {
> +			/*
> +			 * Preclude splitting current to FLED2 if we
> +			 * are driving two separate leds.
> +			 */
> +			iout_max[FLED2] = 0;
> +		}
> +		__max77693_calc_iout(iout, micro_amp, iout_max);
> +	} else if (fled_id == FLED2) {
> +		/*
> +		 * Preclude splitting current to FLED1 if we
> +		 * are driving two separate leds.
> +		 */
> +		iout_max[FLED1] = 0;
> +		__max77693_calc_iout(iout, micro_amp, iout_max);
> +	}
> +}
> +
> +static int max77693_set_torch_current(struct max77693_led_device *led,
> +				int fled_id, u32 micro_amp)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct regmap *rmap = led->regmap;
> +	u32 iout[2], iout_max[2];
> +	u8 iout1_reg = 0, iout2_reg = 0;
> +
> +	iout_max[FLED1] = cfg->iout_torch[FLED1];
> +	iout_max[FLED2] = cfg->iout_torch[FLED2];
> +
> +	led->allowed_modes |= MODE_TORCH_MASK;
> +
> +	max77693_calc_iout(led, fled_id, iout, micro_amp, iout_max,

Could you use cfg->iout_torch directly?

> +				TORCH);
> +
> +	if (fled_id == FLED1 || led->iout_joint) {
> +		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);
> +		led->torch_iout_reg &= 0xf0;

I think it'd be cleaner to use register bit names and led-specific shift
here. Up to you.

> +	}
> +	if (fled_id == FLED2 || led->iout_joint) {
> +		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);
> +		led->torch_iout_reg &= 0x0f;
> +	}
> +
> +	led->torch_iout_reg |= ((iout1_reg << TORCH_IOUT1_SHIFT) |
> +				(iout2_reg << TORCH_IOUT2_SHIFT));
> +
> +	return regmap_write(rmap, MAX77693_LED_REG_ITORCH,
> +						led->torch_iout_reg);
> +}
> +
> +static int max77693_set_flash_current(struct max77693_led_device *led,
> +					int fled_id,
> +					u32 micro_amp)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct regmap *rmap = led->regmap;
> +	u32 iout[2], iout_max[2];
> +	u8 iout1_reg, iout2_reg;
> +	int ret = -EINVAL;
> +
> +	iout_max[FLED1] = cfg->iout_flash[FLED1];
> +	iout_max[FLED2] = cfg->iout_flash[FLED2];
> +
> +	led->allowed_modes |= MODE_FLASH_MASK;
> +
> +	max77693_calc_iout(led, fled_id, iout, micro_amp, iout_max,
> +				FLASH);
> +
> +	if (fled_id == FLED1 || led->iout_joint) {
> +		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);
> +		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH1,
> +							iout1_reg);
> +		if (ret < 0)
> +			return ret;
> +	}
> +	if (fled_id == FLED2 || led->iout_joint) {
> +		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);
> +		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH2,
> +							iout2_reg);
> +	}
> +
> +	return ret;
> +}
> +
> +static int max77693_set_timeout(struct max77693_led_device *led, u32 microsec)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct regmap *rmap = led->regmap;
> +	u8 v;
> +	int ret;
> +
> +	v = max77693_flash_timeout_to_reg(microsec);
> +
> +	if (cfg->trigger_type == MAX77693_LED_TRIG_TYPE_LEVEL)
> +		v |= FLASH_TMR_LEVEL;
> +
> +	ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_TIMER, v);
> +	if (ret < 0)
> +		return ret;
> +
> +	led->current_flash_timeout = microsec;
> +
> +	return 0;
> +}
> +
> +static int max77693_strobe_status_get(struct max77693_led_device *led,
> +					bool *state)
> +{
> +	struct regmap *rmap = led->regmap;
> +	unsigned int v;
> +	int ret;
> +
> +	ret = regmap_read(rmap, MAX77693_LED_REG_FLASH_STATUS, &v);
> +	if (ret < 0)
> +		return ret;
> +
> +	*state = v & FLASH_STATUS_FLASH_ON;
> +
> +	return ret;
> +}
> +
> +static int max77693_int_flag_get(struct max77693_led_device *led,
> +					unsigned int *v)
> +{
> +	struct regmap *rmap = led->regmap;
> +
> +	return regmap_read(rmap, MAX77693_LED_REG_FLASH_INT, v);
> +}
> +
> +static int max77693_setup(struct max77693_led_device *led)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct regmap *rmap = led->regmap;
> +	int i, first_led, last_led, ret;
> +	u32 max_flash_curr[2];
> +	u8 v;
> +
> +	/*
> +	 * Initialize only flash current. Torch current doesn't
> +	 * require initialization as ITORCH register is written with
> +	 * new value each time brightness_set op is called.
> +	 */
> +	if (led->iout_joint) {
> +		first_led = FLED1;
> +		last_led = FLED1;
> +		max_flash_curr[FLED1] = cfg->iout_flash[FLED1] +
> +					cfg->iout_flash[FLED2];
> +	} else {
> +		first_led = max77693_fled_used(led, FLED1) ? FLED1 : FLED2;
> +		last_led = led->cfg_data->num_leds == 2 ? FLED2 : first_led;
> +		max_flash_curr[FLED1] = cfg->iout_flash[FLED1];
> +		max_flash_curr[FLED2] = cfg->iout_flash[FLED2];
> +	}
> +
> +	for (i = first_led; i <= last_led; ++i) {
> +		ret = max77693_set_flash_current(led, i,
> +					max_flash_curr[i]);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	v = TORCH_TMR_NO_TIMER | MAX77693_LED_TRIG_TYPE_LEVEL;
> +	ret = regmap_write(rmap, MAX77693_LED_REG_ITORCHTIMER, v);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* initially set FLED1 timeout */
> +	ret = max77693_set_timeout(led, cfg->flash_timeout[FLED1]);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (cfg->low_vsys > 0)
> +		v = max77693_led_vsys_to_reg(cfg->low_vsys) |
> +						MAX_FLASH1_MAX_FL_EN;
> +	else
> +		v = 0;
> +
> +	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH1, v);
> +	if (ret < 0)
> +		return ret;
> +	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH2, 0);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (cfg->boost_mode == MAX77693_LED_BOOST_FIXED)
> +		v = FLASH_BOOST_FIXED;
> +	else
> +		v = cfg->boost_mode | cfg->boost_mode << 1;
> +
> +	if (max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))
> +		v |= FLASH_BOOST_LEDNUM_2;
> +
> +	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_CNTL, v);
> +	if (ret < 0)
> +		return ret;
> +
> +	v = max77693_led_vout_to_reg(cfg->boost_vout);
> +	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_FLASH1, v);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Allow all modes on both fled outputs */
> +	led->allowed_modes = MODE_FLASH_MASK | MODE_TORCH_MASK;
> +
> +	return max77693_set_mode(led, MODE_OFF);
> +}
> +
> +static int __max77693_led_brightness_set(struct max77693_led_device *led,
> +					int fled_id, enum led_brightness value)
> +{
> +	int ret;
> +
> +	mutex_lock(&led->lock);
> +
> +	if (value == 0) {
> +		ret = max77693_clear_mode(led, MODE_TORCH(fled_id));
> +		if (ret < 0)
> +			dev_dbg(&led->pdev->dev,
> +				"Failed to clear torch mode (%d)\n",
> +				ret);
> +		goto unlock;
> +	}
> +
> +	ret = max77693_set_torch_current(led, fled_id, value * TORCH_IOUT_STEP);
> +	if (ret < 0) {
> +		dev_dbg(&led->pdev->dev,
> +			"Failed to set torch current (%d)\n",
> +			ret);
> +		goto unlock;
> +	}
> +
> +	ret = max77693_add_mode(led, MODE_TORCH(fled_id));
> +	if (ret < 0)
> +		dev_dbg(&led->pdev->dev,
> +			"Failed to set torch mode (%d)\n",
> +			ret);
> +unlock:
> +	mutex_unlock(&led->lock);
> +	return ret;
> +}
> +
> +static void max77693_led_brightness_set_work(
> +					struct work_struct *work)
> +{
> +	struct max77693_sub_led *sub_led =
> +			container_of(work, struct max77693_sub_led,
> +					work_brightness_set);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +
> +	__max77693_led_brightness_set(led, sub_led->fled_id,
> +				sub_led->torch_brightness);
> +}
> +
> +/* LED subsystem callbacks */
> +
> +static int max77693_led_brightness_set_sync(
> +				struct led_classdev *led_cdev,
> +				enum led_brightness value)
> +{
> +	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +
> +	return __max77693_led_brightness_set(led, sub_led->fled_id, value);
> +}
> +
> +static void max77693_led_brightness_set(
> +				struct led_classdev *led_cdev,
> +				enum led_brightness value)
> +{
> +	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +
> +	sub_led->torch_brightness = value;
> +	schedule_work(&sub_led->work_brightness_set);
> +}
> +
> +static int max77693_led_flash_brightness_set(
> +				struct led_classdev_flash *fled_cdev,
> +				u32 brightness)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +	int ret;
> +
> +	mutex_lock(&led->lock);
> +	ret = max77693_set_flash_current(led, sub_led->fled_id, brightness);
> +	mutex_unlock(&led->lock);
> +
> +	return ret;
> +}
> +
> +static int max77693_led_flash_strobe_set(
> +				struct led_classdev_flash *fled_cdev,
> +				bool state)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(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 (!state) {
> +		ret = max77693_clear_mode(led, MODE_FLASH(fled_id));
> +		goto unlock;
> +	}
> +
> +	if (sub_led->flash_timeout != led->current_flash_timeout) {
> +		ret = max77693_set_timeout(led, sub_led->flash_timeout);
> +		if (ret < 0)
> +			goto unlock;
> +	}
> +
> +	led->strobing_sub_led_id = fled_id;
> +
> +	ret = max77693_add_mode(led, MODE_FLASH(fled_id));
> +
> +unlock:
> +	mutex_unlock(&led->lock);
> +	return ret;
> +}
> +
> +static int max77693_led_flash_fault_get(
> +				struct led_classdev_flash *fled_cdev,
> +				u32 *fault)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +	unsigned int v;
> +	int ret;
> +
> +	ret = max77693_int_flag_get(led, &v);
> +	if (ret < 0)
> +		return ret;
> +
> +	*fault = 0;
> +
> +	if (v & ((sub_led->fled_id == FLED1) ? FLASH_INT_FLED1_OPEN :
> +					       FLASH_INT_FLED2_OPEN))
> +		*fault |= LED_FAULT_OVER_VOLTAGE;
> +	if (v & ((sub_led->fled_id == FLED1) ? FLASH_INT_FLED1_SHORT :
> +					       FLASH_INT_FLED2_SHORT))
> +		*fault |= LED_FAULT_SHORT_CIRCUIT;
> +	if (v & FLASH_INT_OVER_CURRENT)
> +		*fault |= LED_FAULT_OVER_CURRENT;
> +
> +	return 0;
> +}
> +
> +static int max77693_led_flash_strobe_get(
> +				struct led_classdev_flash *fled_cdev,
> +				bool *state)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +	int ret;
> +
> +	if (!state)
> +		return -EINVAL;
> +
> +	mutex_lock(&led->lock);
> +
> +	ret = max77693_strobe_status_get(led, state);
> +
> +	*state = !!(*state && (led->strobing_sub_led_id == sub_led->fled_id));
> +
> +
> +	mutex_unlock(&led->lock);
> +
> +	return ret;
> +}
> +
> +static int max77693_led_flash_timeout_set(
> +				struct led_classdev_flash *fled_cdev,
> +				u32 timeout)
> +{
> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
> +
> +	mutex_lock(&led->lock);
> +	sub_led->flash_timeout = timeout;
> +	mutex_unlock(&led->lock);
> +
> +	return 0;
> +}
> +
> +static int max77693_led_parse_dt(struct max77693_led_device *led,
> +				 struct device_node *node)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct max77693_sub_led *sub_leds = led->sub_leds;
> +	struct device *dev = &led->pdev->dev;
> +	struct device_node *child_node;
> +	u32 led_sources[2];
> +	int fled_id, ret;
> +
> +	of_property_read_u32(node, "maxim,trigger-type", &cfg->trigger_type);
> +	of_property_read_u32(node, "maxim,boost-mode", &cfg->boost_mode);
> +	of_property_read_u32(node, "maxim,boost-vout", &cfg->boost_vout);
> +	of_property_read_u32(node, "maxim,vsys-min", &cfg->low_vsys);
> +
> +	for_each_available_child_of_node(node, child_node) {
> +		ret = of_property_read_u32_array(child_node, "led-sources",
> +							led_sources, 2);
> +		if (ret < 0) {
> +			dev_err(dev,
> +				"Error reading \"led-sources\" DT property\n");
> +			return ret;
> +		}
> +
> +		if (led_sources[0] && led_sources[1]) {
> +			fled_id = FLED1;
> +			led->fled_mask = FLED1_IOUT | FLED2_IOUT;
> +		} else if (led_sources[0] && !led_sources[1]) {
> +			fled_id = FLED1;
> +			led->fled_mask |= FLED1_IOUT;
> +		} else if (!led_sources[0] && led_sources[1]) {
> +			fled_id = FLED2;
> +			led->fled_mask |= FLED2_IOUT;
> +		} else {
> +			dev_err(dev,
> +				"Wrong \"led-sources\" DT property value\n");
> +			return -EINVAL;
> +		}
> +
> +		sub_leds[fled_id].fled_id = fled_id;
> +
> +		ret = of_property_read_string(child_node, "label",
> +					(const char **) &cfg->label[fled_id]);
> +		if (ret < 0) {
> +			dev_err(dev, "Error reading \"label\" DT property\n");
> +			return ret;
> +		}
> +
> +		of_property_read_u32(child_node, "max-microamp",
> +						&cfg->iout_torch[fled_id]);
> +		of_property_read_u32(child_node, "flash-max-microamp",
> +						&cfg->iout_flash[fled_id]);
> +		of_property_read_u32(child_node, "flash-timeout-us",
> +						&cfg->flash_timeout[fled_id]);
> +
> +		if (++led->cfg_data->num_leds == 2 ||
> +		    (max77693_fled_used(led, FLED1) &&
> +		     max77693_fled_used(led, FLED2)))
> +			break;
> +	}
> +
> +	return 0;
> +}
> +
> +static void clamp_align(u32 *v, u32 min, u32 max, u32 step)
> +{
> +	*v = clamp_val(*v, min, max);
> +	if (step > 1)
> +		*v = (*v - min) / step * step + min;
> +}
> +
> +static void max77693_led_validate_configuration(struct max77693_led_device *led)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	int i;
> +
> +	if (led->cfg_data->num_leds == 1 &&
> +	    max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))
> +		led->iout_joint = true;
> +
> +	cfg->boost_mode = clamp_val(cfg->boost_mode, MAX77693_LED_BOOST_NONE,
> +			    MAX77693_LED_BOOST_FIXED);
> +
> +	/* Boost must be enabled if both current outputs are used */
> +	if ((cfg->boost_mode == MAX77693_LED_BOOST_NONE) && led->iout_joint)
> +		cfg->boost_mode = MAX77693_LED_BOOST_FIXED;
> +
> +	/* Split max current settings to both outputs in case of joint leds */
> +	if (led->iout_joint) {
> +		cfg->iout_torch[FLED1] /= 2;
> +		cfg->iout_torch[FLED2] = cfg->iout_torch[FLED1];
> +		cfg->iout_flash[FLED1] /= 2;
> +		cfg->iout_flash[FLED2] = cfg->iout_flash[FLED1];
> +	}
> +
> +	for (i = FLED1; i <= FLED2; ++i) {
> +		if (max77693_fled_used(led, i)) {
> +			clamp_align(&cfg->iout_torch[i], TORCH_IOUT_MIN,
> +					TORCH_IOUT_MAX, TORCH_IOUT_STEP);
> +			clamp_align(&cfg->iout_flash[i], FLASH_IOUT_MIN,
> +					cfg->boost_mode ? FLASH_IOUT_MAX_2LEDS :
> +							FLASH_IOUT_MAX_1LED,
> +					FLASH_IOUT_STEP);
> +		} else {
> +			cfg->iout_torch[i] = cfg->iout_flash[i] = 0;
> +		}
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(cfg->flash_timeout); ++i)
> +		clamp_align(&cfg->flash_timeout[i], FLASH_TIMEOUT_MIN,
> +				FLASH_TIMEOUT_MAX, FLASH_TIMEOUT_STEP);
> +
> +	cfg->trigger_type = clamp_val(cfg->trigger_type,
> +					MAX77693_LED_TRIG_TYPE_EDGE,
> +					MAX77693_LED_TRIG_TYPE_LEVEL);
> +
> +	clamp_align(&cfg->boost_vout, FLASH_VOUT_MIN, FLASH_VOUT_MAX,
> +							FLASH_VOUT_STEP);
> +
> +	if (cfg->low_vsys)
> +		clamp_align(&cfg->low_vsys, MAX_FLASH1_VSYS_MIN,
> +				MAX_FLASH1_VSYS_MAX, MAX_FLASH1_VSYS_STEP);
> +}
> +
> +static int max77693_led_get_configuration(struct max77693_led_device *led)
> +{
> +	struct device *dev = &led->pdev->dev;
> +	int ret;
> +
> +	if (!dev->of_node)
> +		return -EINVAL;
> +
> +	led->cfg_data = devm_kzalloc(dev, sizeof(*led->cfg_data), GFP_KERNEL);
> +	if (!led->cfg_data)
> +		return -ENOMEM;
> +
> +	ret = max77693_led_parse_dt(led, dev->of_node);
> +	if (ret < 0)
> +		return ret;
> +
> +	max77693_led_validate_configuration(led);
> +
> +	return 0;
> +}
> +
> +static const struct led_flash_ops flash_ops = {
> +	.flash_brightness_set	= max77693_led_flash_brightness_set,
> +	.strobe_set		= max77693_led_flash_strobe_set,
> +	.strobe_get		= max77693_led_flash_strobe_get,
> +	.timeout_set		= max77693_led_flash_timeout_set,
> +	.fault_get		= max77693_led_flash_fault_get,
> +};
> +
> +static void max77693_init_flash_settings(struct max77693_led_device *led,
> +					 struct max77693_led_settings *s,
> +					 int fled_id)
> +{
> +	struct max77693_led_config_data *cfg = led->cfg_data;
> +	struct led_flash_setting *setting;
> +
> +	/* Init torch intensity setting */
> +	setting = &s->torch_brightness;
> +	setting->min = TORCH_IOUT_MIN;
> +	setting->max = cfg->iout_torch[fled_id];
> +	setting->max = led->iout_joint ?
> +			cfg->iout_torch[FLED1] + cfg->iout_torch[FLED2] :
> +			cfg->iout_torch[fled_id];
> +	setting->step = TORCH_IOUT_STEP;
> +	setting->val = setting->max;
> +
> +	/* Init flash intensity setting */
> +	setting = &s->flash_brightness;
> +	setting->min = FLASH_IOUT_MIN;
> +	setting->max = led->iout_joint ?
> +			cfg->iout_flash[FLED1] + cfg->iout_flash[FLED2] :
> +			cfg->iout_flash[fled_id];
> +	setting->step = FLASH_IOUT_STEP;
> +	setting->val = setting->max;
> +
> +	/* Init flash timeout setting */
> +	setting = &s->flash_timeout;
> +	setting->min = FLASH_TIMEOUT_MIN;
> +	setting->max = cfg->flash_timeout[fled_id];
> +	setting->step = FLASH_TIMEOUT_STEP;
> +	setting->val = setting->max;
> +}
> +
> +static int max77693_set_available_sync_led(struct max77693_led_device *led,
> +						int fled_id)
> +{
> +	struct max77693_sub_led *sub_led = &led->sub_leds[fled_id];
> +	struct led_classdev_flash *fled_cdev = &sub_led->fled_cdev;
> +
> +	fled_cdev->sync_leds = devm_kzalloc(&led->pdev->dev, sizeof(fled_cdev),
> +					GFP_KERNEL);
> +	if (!fled_cdev->sync_leds)
> +		return -ENOMEM;
> +
> +	fled_cdev->sync_leds[0] = &led->sub_leds[!fled_id].fled_cdev;
> +	fled_cdev->num_sync_leds = 1;
> +
> +	return 0;
> +}
> +
> +static void max77693_init_fled_cdev(struct max77693_led_device *led,
> +					int fled_id)
> +{
> +	struct led_classdev_flash *fled_cdev;
> +	struct led_classdev *led_cdev;
> +	struct max77693_sub_led *sub_led = &led->sub_leds[fled_id];
> +	struct max77693_led_settings settings;
> +
> +	/* Initialize flash settings */
> +	max77693_init_flash_settings(led, &settings, fled_id);
> +
> +	/* Initialize LED Flash class device */
> +	fled_cdev = &sub_led->fled_cdev;
> +	fled_cdev->ops = &flash_ops;
> +	led_cdev = &fled_cdev->led_cdev;
> +	led_cdev->name = led->cfg_data->label[fled_id];
> +	led_cdev->brightness_set = max77693_led_brightness_set;
> +	led_cdev->brightness_set_sync = max77693_led_brightness_set_sync;
> +	INIT_WORK(&sub_led->work_brightness_set,
> +			max77693_led_brightness_set_work);
> +
> +	led_cdev->max_brightness = settings.torch_brightness.val /
> +					TORCH_IOUT_STEP;
> +	led_cdev->flags |= LED_DEV_CAP_FLASH;
> +	if (led->cfg_data->num_leds == 2)
> +		led_cdev->flags |= LED_DEV_CAP_SYNC_STROBE;
> +
> +	fled_cdev->brightness = settings.flash_brightness;
> +	fled_cdev->timeout = settings.flash_timeout;
> +	sub_led->flash_timeout = fled_cdev->timeout.val;
> +}
> +
> +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;
> +	int init_fled_cdev[2], i, ret;
> +
> +	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
> +	if (!led)
> +		return -ENOMEM;
> +
> +	led->pdev = pdev;
> +	led->regmap = iodev->regmap;
> +	sub_leds = led->sub_leds;
> +
> +	platform_set_drvdata(pdev, led);
> +	ret = max77693_led_get_configuration(led);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = max77693_setup(led);
> +	if (ret < 0)
> +		return ret;
> +
> +	init_fled_cdev[FLED1] =
> +			led->iout_joint || max77693_fled_used(led, FLED1);
> +	init_fled_cdev[FLED2] =
> +			!led->iout_joint && max77693_fled_used(led, FLED2);
> +
> +	/* Initialize LED Flash class device(s) */
> +	for (i = FLED1; i <= FLED2; ++i)
> +		if (init_fled_cdev[i])
> +			max77693_init_fled_cdev(led, i);
> +
> +	/* Setup sub-leds available for flash strobe synchronization */
> +	if (led->cfg_data->num_leds == 2) {
> +		for (i = FLED1; i <= FLED2; ++i) {
> +			ret = max77693_set_available_sync_led(led, i);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
> +	mutex_init(&led->lock);
> +
> +	/* Register LED Flash class device(s) */
> +	for (i = FLED1; i <= FLED2; ++i) {
> +		if (init_fled_cdev[i]) {

if (!...)
	continue;

The rest of the loop would look nicer this way I think. Up to you.

> +			ret = led_classdev_flash_register(dev,
> +							&sub_leds[i].fled_cdev);
> +			if (ret < 0) {
> +				/*
> +				 * At this moment FLED1 might have been already
> +				 * registered and it needs to be released.
> +				 */
> +				if (i == FLED2)
> +					goto err_register_led2;
> +				else
> +					goto err_register_led1;
> +			}
> +		}
> +	}
> +
> +
> +	return 0;
> +
> +err_register_led2:
> +	/* It is possible than only FLED2 was to be registered */
> +	if (!init_fled_cdev[FLED1])
> +		goto err_register_led1;
> +	led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
> +err_register_led1:
> +	mutex_destroy(&led->lock);
> +
> +	return ret;
> +}
> +
> +static int max77693_led_remove(struct platform_device *pdev)
> +{
> +	struct max77693_led_device *led = platform_get_drvdata(pdev);
> +	struct max77693_sub_led *sub_leds = led->sub_leds;
> +
> +	if (led->iout_joint || max77693_fled_used(led, FLED1)) {
> +		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)) {
> +		led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);
> +		cancel_work_sync(&sub_leds[FLED2].work_brightness_set);
> +	}
> +
> +	mutex_destroy(&led->lock);
> +
> +	return 0;
> +}
> +
> +static struct of_device_id max77693_led_dt_match[] = {
> +	{.compatible = "maxim,max77693-led"},
> +	{},
> +};
> +
> +static struct platform_driver max77693_led_driver = {
> +	.probe		= max77693_led_probe,
> +	.remove		= max77693_led_remove,
> +	.driver		= {
> +		.name	= "max77693-led",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = max77693_led_dt_match,
> +	},
> +};
> +
> +module_platform_driver(max77693_led_driver);
> +
> +MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
> +MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
> +MODULE_DESCRIPTION("Maxim MAX77693 led flash driver");
> +MODULE_LICENSE("GPL v2");

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell
  2015-02-05 15:34       ` Sakari Ailus
  (?)
@ 2015-02-05 16:26       ` Jacek Anaszewski
  -1 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-02-05 16:26 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, s.nawrocki,
	Andrzej Hajda, Lee Jones, Chanwoo Choi

Hi Sakari,

Thanks for the review.

On 02/05/2015 04:34 PM, Sakari Ailus wrote:
> Hi Jacek,
>
> A few comments below.
>
> On Fri, Jan 09, 2015 at 04:22:58PM +0100, Jacek Anaszewski wrote:
>> This patch adds led-flash support to Maxim max77693 chipset.
>> A device can be exposed to user space through LED subsystem
>> sysfs interface. Device supports up to two leds which can
>> work in flash and torch mode. The leds can be triggered
>> externally or by software.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> Cc: Bryan Wu <cooloney@gmail.com>
>> Cc: Richard Purdie <rpurdie@rpsys.net>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Cc: Chanwoo Choi <cw00.choi@samsung.com>
>> ---
>>   drivers/leds/Kconfig         |   10 +
>>   drivers/leds/Makefile        |    1 +
>>   drivers/leds/leds-max77693.c | 1045 ++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 1056 insertions(+)
>>   create mode 100644 drivers/leds/leds-max77693.c
>>
>> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
>> index 95029df..ff9c21b 100644
>> --- a/drivers/leds/Kconfig
>> +++ b/drivers/leds/Kconfig
>> @@ -464,6 +464,16 @@ config LEDS_TCA6507
>>   	  LED driver chips accessed via the I2C bus.
>>   	  Driver support brightness control and hardware-assisted blinking.
>>
>> +config LEDS_MAX77693
>> +	tristate "LED support for MAX77693 Flash"
>> +	depends on LEDS_CLASS_FLASH
>> +	depends on MFD_MAX77693
>> +	depends on OF
>> +	help
>> +	  This option enables support for the flash part of the MAX77693
>> +	  multifunction device. It has build in control for two leds in flash
>> +	  and torch mode.
>> +
>>   config LEDS_MAX8997
>>   	tristate "LED support for MAX8997 PMIC"
>>   	depends on LEDS_CLASS && MFD_MAX8997
>> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
>> index cbba921..57ca62b 100644
>> --- a/drivers/leds/Makefile
>> +++ b/drivers/leds/Makefile
>> @@ -52,6 +52,7 @@ obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
>>   obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
>>   obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
>>   obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
>> +obj-$(CONFIG_LEDS_MAX77693)		+= leds-max77693.o
>>   obj-$(CONFIG_LEDS_MAX8997)		+= leds-max8997.o
>>   obj-$(CONFIG_LEDS_LM355x)		+= leds-lm355x.o
>>   obj-$(CONFIG_LEDS_BLINKM)		+= leds-blinkm.o
>> diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
>> new file mode 100644
>> index 0000000..3ba07c4
>> --- /dev/null
>> +++ b/drivers/leds/leds-max77693.c
>> @@ -0,0 +1,1045 @@
>> +/*
>> + * LED Flash class driver for the flash cell of max77693 mfd.
>> + *
>> + *	Copyright (C) 2015, Samsung Electronics Co., Ltd.
>> + *
>> + *	Authors: Jacek Anaszewski <j.anaszewski@samsung.com>
>> + *		 Andrzej Hajda <a.hajda@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * version 2 as published by the Free Software Foundation.
>> + */
>> +
>> +#include <asm/div64.h>
>> +#include <linux/led-class-flash.h>
>> +#include <linux/mfd/max77693.h>
>> +#include <linux/mfd/max77693-private.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regmap.h>
>> +#include <linux/slab.h>
>> +#include <linux/workqueue.h>
>> +
>> +#define MODE_OFF		0
>> +#define MODE_FLASH(a)		(1 << (a))
>> +#define MODE_TORCH(a)		(1 << (2 + (a)))
>> +#define MODE_FLASH_EXTERNAL(a)	(1 << (4 + (a)))
>> +
>> +#define MODE_FLASH_MASK		(MODE_FLASH(FLED1) | MODE_FLASH(FLED2) | \
>> +				 MODE_FLASH_EXTERNAL(FLED1) | \
>> +				 MODE_FLASH_EXTERNAL(FLED2))
>> +#define MODE_TORCH_MASK		(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))
>> +
>> +#define FLED1_IOUT		(1 << 0)
>> +#define FLED2_IOUT		(1 << 1)
>> +
>> +enum max77693_fled {
>> +	FLED1,
>> +	FLED2,
>> +};
>> +
>> +enum max77693_led_mode {
>> +	FLASH,
>> +	TORCH,
>> +};
>> +
>> +struct max77693_sub_led {
>> +	/* related FLED output identifier */
>> +	int fled_id;
>> +	/* related LED Flash class device */
>> +	struct led_classdev_flash fled_cdev;
>> +	/* assures led-triggers compatibility */
>> +	struct work_struct work_brightness_set;
>> +
>> +	/* brightness cache */
>> +	unsigned int torch_brightness;
>> +	/* flash timeout cache */
>> +	unsigned int flash_timeout;
>> +};
>> +
>> +struct max77693_led_device {
>> +	/* parent mfd regmap */
>> +	struct regmap *regmap;
>> +	/* platform device data */
>> +	struct platform_device *pdev;
>> +	/* configuration data for the device */
>> +	struct max77693_led_config_data *cfg_data;
>
> Where is this defined?

In the file include/linux/mfd/max77693.h. The original
struct max77693_led_platform_data was defined there
and one of the preceding patches in this patch set renames it.

>> +	/* secures access to the device */
>> +	struct mutex lock;
>> +
>> +	/* sub led data */
>> +	struct max77693_sub_led sub_leds[2];
>> +
>> +	/* current flash timeout cache */
>> +	unsigned int current_flash_timeout;
>> +	/* ITORCH register cache */
>> +	u8 torch_iout_reg;
>> +	/* mode of fled outputs */
>> +	unsigned int mode_flags;
>> +	/* recently strobed fled */
>> +	int strobing_sub_led_id;
>> +	/* bitmask of fled outputs use state (bit 0. - FLED1, bit 1. - FLED2) */
>> +	u8 fled_mask;
>> +	/* fled modes that can be set */
>> +	u8 allowed_modes;
>> +
>> +	/* arrangement of current outputs */
>> +	bool iout_joint;
>> +};
>> +
>> +struct max77693_led_settings {
>> +	struct led_flash_setting torch_brightness;
>> +	struct led_flash_setting flash_brightness;
>> +	struct led_flash_setting flash_timeout;
>> +};
>> +
>> +static u8 max77693_led_iout_to_reg(u32 ua)
>> +{
>> +	if (ua < FLASH_IOUT_MIN)
>> +		ua = FLASH_IOUT_MIN;
>> +	return (ua - FLASH_IOUT_MIN) / FLASH_IOUT_STEP;
>> +}
>> +
>> +static u8 max77693_flash_timeout_to_reg(u32 us)
>> +{
>> +	return (us - FLASH_TIMEOUT_MIN) / FLASH_TIMEOUT_STEP;
>> +}
>> +
>> +static inline struct max77693_sub_led *flcdev_to_sub_led(
>> +					struct led_classdev_flash *fled_cdev)
>> +{
>> +	return container_of(fled_cdev, struct max77693_sub_led, fled_cdev);
>> +}
>> +
>> +static inline struct max77693_led_device *sub_led_to_led(
>> +					struct max77693_sub_led *sub_led)
>> +{
>> +	return container_of(sub_led, struct max77693_led_device,
>> +				sub_leds[sub_led->fled_id]);
>> +}
>> +
>> +static inline u8 max77693_led_vsys_to_reg(u32 mv)
>> +{
>> +	return ((mv - MAX_FLASH1_VSYS_MIN) / MAX_FLASH1_VSYS_STEP) << 2;
>> +}
>> +
>> +static inline u8 max77693_led_vout_to_reg(u32 mv)
>> +{
>> +	return (mv - FLASH_VOUT_MIN) / FLASH_VOUT_STEP + FLASH_VOUT_RMIN;
>> +}
>> +
>> +static inline bool max77693_fled_used(struct max77693_led_device *led,
>> +					 int fled_id)
>> +{
>> +	u8 fled_bit = (fled_id == FLED1) ? FLED1_IOUT : FLED2_IOUT;
>> +
>> +	return led->fled_mask & fled_bit;
>> +}
>> +
>> +/* split composite current @i into two @iout according to @imax weights */
>
> Do you still consider this as the right thing to do?
>
> If there's a single LED driven by multiple outputs, what is the value
> provided by board-specific current distribution between these outputs?

This is required for being able to set odd current levels, in case
one led is connected to both outputs. The currents are still being set
separately for both outputs. For example, if we want to set LED
subsystem brightness level == 3, then we have to set e.g. register
MAX77693_LED_REG_IFLASH1 to 0 and MAX77693_LED_REG_IFLASH1 to 1
(where levels start from 0 (15.625mA) in the max77693-led device).

I think that we've agreed about this on #v4l.

>> +static void __max77693_calc_iout(u32 iout[2], u32 i, u32 imax[2])
>> +{
>> +	u64 t = i;
>> +
>> +	t *= imax[1];
>> +	do_div(t, imax[0] + imax[1]);
>> +
>> +	iout[1] = (u32)t / FLASH_IOUT_STEP * FLASH_IOUT_STEP;
>> +	iout[0] = i - iout[1];
>> +}
>> +
>> +static int max77693_set_mode(struct max77693_led_device *led, u8 mode)
>> +{
>> +	struct regmap *rmap = led->regmap;
>> +	int ret, v = 0, i;
>> +
>> +	for (i = FLED1; i <= FLED2; ++i) {
>> +		if (mode & MODE_TORCH(i))
>> +			v |= FLASH_EN_ON << TORCH_EN_SHIFT(i);
>> +
>> +		if (mode & MODE_FLASH(i)) {
>> +			v |= FLASH_EN_ON << FLASH_EN_SHIFT(i);
>> +		} else if (mode & MODE_FLASH_EXTERNAL(i)) {
>> +			v |= FLASH_EN_FLASH << FLASH_EN_SHIFT(i);
>> +			/*
>> +			 * Enable hw triggering also for torch mode, as some
>> +			 * camera sensors use torch led to fathom ambient light
>> +			 * conditions before strobing the flash.
>> +			 */
>> +			v |= FLASH_EN_TORCH << TORCH_EN_SHIFT(i);
>> +		}
>> +	}
>> +
>> +	/* Reset the register only prior setting flash modes */
>> +	if (mode & ~(MODE_TORCH(FLED1) | MODE_TORCH(FLED2))) {
>> +		ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, 0);
>> +		if (ret < 0)
>> +			return ret;
>> +	}
>> +
>> +	return regmap_write(rmap, MAX77693_LED_REG_FLASH_EN, v);
>> +}
>> +
>> +static void max77693_set_sync_strobe(struct max77693_led_device *led,
>> +					u8 *mode)
>> +{
>> +	struct max77693_sub_led *sub_leds = led->sub_leds;
>> +	struct led_classdev_flash *fled_cdev;
>> +	u8 m = *mode;
>> +
>> +	if (led->iout_joint)
>> +		return;
>> +
>> +	/* Check if the other sub-led wants to be strobed simultaneously. */
>> +	if (m & (MODE_FLASH(FLED1) | MODE_FLASH_EXTERNAL(FLED1))) {
>> +		fled_cdev = &sub_leds[FLED2].fled_cdev;
>> +		if (fled_cdev->sync_led_id)
>> +			m |= m << 1;
>> +	} else if (m & (MODE_FLASH(FLED2) | MODE_FLASH_EXTERNAL(FLED2))) {
>> +		fled_cdev = &sub_leds[FLED1].fled_cdev;
>> +		if (fled_cdev->sync_led_id)
>> +			m |= m >> 1;
>> +	}
>> +
>> +	*mode = m;
>> +}
>> +
>> +static int max77693_add_mode(struct max77693_led_device *led, u8 mode)
>> +{
>> +	int i, ret;
>> +
>> +	mode &= led->allowed_modes;
>> +
>> +	/*
>> +	 * Torch mode once enabled remains active until turned off. If the FLED2
>> +	 * output isn't to be disabled check if the torch mode to be set isn't
>> +	 * already activated and avoid re-setting it.
>> +	 */
>> +	if ((!(mode ^ led->mode_flags)) & MODE_TORCH(FLED2)) {
>> +		for (i = FLED1; i <= FLED2; ++i)
>> +			if ((mode & MODE_TORCH(i)) &&
>> +			    (led->mode_flags & MODE_TORCH(i)))
>> +				return 0;
>> +	}
>> +
>> +	/* Span the mode on FLED2 for joint iouts case */
>> +	if (led->iout_joint)
>> +		mode |= (mode << 1);
>> +
>> +	/* Span the flash mode on the other led if it is to be synchronized */
>> +	max77693_set_sync_strobe(led, &mode);
>> +
>> +	/*
>> +	 * FLASH_EXTERNAL mode activates FLASHEN and TORCHEN pins in the device.
>> +	 * The related register bits fields interfere with SW triggerred modes,
>> +	 * thus clear them to ensure proper device configuration.
>> +	 */
>> +	for (i = FLED1; i <= FLED2; ++i)
>> +		if (mode & MODE_FLASH_EXTERNAL(i))
>> +			led->mode_flags &= (~MODE_TORCH(i) & ~MODE_FLASH(i));
>> +
>> +	led->mode_flags |= mode;
>> +	led->mode_flags &= led->allowed_modes;
>> +
>> +	ret = max77693_set_mode(led, led->mode_flags);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	/*
>> +	 * Clear flash mode flag after setting the mode to avoid spurious flash
>> +	 * strobing on each subsequent torch mode setting.
>> +	 */
>> +	if (mode & MODE_FLASH_MASK)
>> +		led->mode_flags &= ~mode;
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77693_clear_mode(struct max77693_led_device *led,
>> +				u8 mode)
>> +{
>> +	int ret;
>> +
>> +	if (led->iout_joint)
>> +		/* Clear mode also on FLED2 for joint iouts case */
>> +		mode |= (mode << 1);
>> +	else
>> +		/*
>> +		 * Clear a flash mode on the other led
>> +		 * if it is to be synchronized.
>> +		 */
>> +		max77693_set_sync_strobe(led, &mode);
>> +
>> +	led->mode_flags &= ~mode;
>> +
>> +	ret = max77693_set_mode(led, led->mode_flags);
>> +
>> +	return ret;
>> +}
>> +
>> +static void max77693_calc_iout(struct max77693_led_device *led, int fled_id,
>> +				u32 iout[2], u32 micro_amp, u32 iout_max[2],
>> +				enum max77693_led_mode mode)
>> +{
>> +	u8 blocked_modes;
>> +
>> +	if (fled_id == FLED1) {
>> +		if (led->iout_joint) {
>> +			/*
>> +			 * FLED2 must not be turned on to get
>> +			 * 15625 uA of total current.
>> +			 */
>> +			if (micro_amp == FLASH_IOUT_MIN) {
>> +				if (mode == FLASH)
>> +					blocked_modes =
>> +						MODE_FLASH(FLED2) |
>> +						MODE_FLASH_EXTERNAL(FLED2);
>> +				else
>> +					blocked_modes = MODE_TORCH(FLED2);
>> +
>> +				led->allowed_modes &= ~blocked_modes;
>> +			}
>> +		} else {
>> +			/*
>> +			 * Preclude splitting current to FLED2 if we
>> +			 * are driving two separate leds.
>> +			 */
>> +			iout_max[FLED2] = 0;
>> +		}
>> +		__max77693_calc_iout(iout, micro_amp, iout_max);
>> +	} else if (fled_id == FLED2) {
>> +		/*
>> +		 * Preclude splitting current to FLED1 if we
>> +		 * are driving two separate leds.
>> +		 */
>> +		iout_max[FLED1] = 0;
>> +		__max77693_calc_iout(iout, micro_amp, iout_max);
>> +	}
>> +}
>> +
>> +static int max77693_set_torch_current(struct max77693_led_device *led,
>> +				int fled_id, u32 micro_amp)
>> +{
>> +	struct max77693_led_config_data *cfg = led->cfg_data;
>> +	struct regmap *rmap = led->regmap;
>> +	u32 iout[2], iout_max[2];
>> +	u8 iout1_reg = 0, iout2_reg = 0;
>> +
>> +	iout_max[FLED1] = cfg->iout_torch[FLED1];
>> +	iout_max[FLED2] = cfg->iout_torch[FLED2];
>> +
>> +	led->allowed_modes |= MODE_TORCH_MASK;
>> +
>> +	max77693_calc_iout(led, fled_id, iout, micro_amp, iout_max,
>
> Could you use cfg->iout_torch directly?

Right, I can't recall why I added redundant iout_max array.

>> +				TORCH);
>> +
>> +	if (fled_id == FLED1 || led->iout_joint) {
>> +		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);
>> +		led->torch_iout_reg &= 0xf0;
>
> I think it'd be cleaner to use register bit names and led-specific shift
> here. Up to you.

Sure.

>> +	}
>> +	if (fled_id == FLED2 || led->iout_joint) {
>> +		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);
>> +		led->torch_iout_reg &= 0x0f;
>> +	}
>> +
>> +	led->torch_iout_reg |= ((iout1_reg << TORCH_IOUT1_SHIFT) |
>> +				(iout2_reg << TORCH_IOUT2_SHIFT));
>> +
>> +	return regmap_write(rmap, MAX77693_LED_REG_ITORCH,
>> +						led->torch_iout_reg);
>> +}
>> +
>> +static int max77693_set_flash_current(struct max77693_led_device *led,
>> +					int fled_id,
>> +					u32 micro_amp)
>> +{
>> +	struct max77693_led_config_data *cfg = led->cfg_data;
>> +	struct regmap *rmap = led->regmap;
>> +	u32 iout[2], iout_max[2];
>> +	u8 iout1_reg, iout2_reg;
>> +	int ret = -EINVAL;
>> +
>> +	iout_max[FLED1] = cfg->iout_flash[FLED1];
>> +	iout_max[FLED2] = cfg->iout_flash[FLED2];
>> +
>> +	led->allowed_modes |= MODE_FLASH_MASK;
>> +
>> +	max77693_calc_iout(led, fled_id, iout, micro_amp, iout_max,
>> +				FLASH);
>> +
>> +	if (fled_id == FLED1 || led->iout_joint) {
>> +		iout1_reg = max77693_led_iout_to_reg(iout[FLED1]);
>> +		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH1,
>> +							iout1_reg);
>> +		if (ret < 0)
>> +			return ret;
>> +	}
>> +	if (fled_id == FLED2 || led->iout_joint) {
>> +		iout2_reg = max77693_led_iout_to_reg(iout[FLED2]);
>> +		ret = regmap_write(rmap, MAX77693_LED_REG_IFLASH2,
>> +							iout2_reg);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77693_set_timeout(struct max77693_led_device *led, u32 microsec)
>> +{
>> +	struct max77693_led_config_data *cfg = led->cfg_data;
>> +	struct regmap *rmap = led->regmap;
>> +	u8 v;
>> +	int ret;
>> +
>> +	v = max77693_flash_timeout_to_reg(microsec);
>> +
>> +	if (cfg->trigger_type == MAX77693_LED_TRIG_TYPE_LEVEL)
>> +		v |= FLASH_TMR_LEVEL;
>> +
>> +	ret = regmap_write(rmap, MAX77693_LED_REG_FLASH_TIMER, v);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	led->current_flash_timeout = microsec;
>> +
>> +	return 0;
>> +}
>> +
>> +static int max77693_strobe_status_get(struct max77693_led_device *led,
>> +					bool *state)
>> +{
>> +	struct regmap *rmap = led->regmap;
>> +	unsigned int v;
>> +	int ret;
>> +
>> +	ret = regmap_read(rmap, MAX77693_LED_REG_FLASH_STATUS, &v);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	*state = v & FLASH_STATUS_FLASH_ON;
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77693_int_flag_get(struct max77693_led_device *led,
>> +					unsigned int *v)
>> +{
>> +	struct regmap *rmap = led->regmap;
>> +
>> +	return regmap_read(rmap, MAX77693_LED_REG_FLASH_INT, v);
>> +}
>> +
>> +static int max77693_setup(struct max77693_led_device *led)
>> +{
>> +	struct max77693_led_config_data *cfg = led->cfg_data;
>> +	struct regmap *rmap = led->regmap;
>> +	int i, first_led, last_led, ret;
>> +	u32 max_flash_curr[2];
>> +	u8 v;
>> +
>> +	/*
>> +	 * Initialize only flash current. Torch current doesn't
>> +	 * require initialization as ITORCH register is written with
>> +	 * new value each time brightness_set op is called.
>> +	 */
>> +	if (led->iout_joint) {
>> +		first_led = FLED1;
>> +		last_led = FLED1;
>> +		max_flash_curr[FLED1] = cfg->iout_flash[FLED1] +
>> +					cfg->iout_flash[FLED2];
>> +	} else {
>> +		first_led = max77693_fled_used(led, FLED1) ? FLED1 : FLED2;
>> +		last_led = led->cfg_data->num_leds == 2 ? FLED2 : first_led;
>> +		max_flash_curr[FLED1] = cfg->iout_flash[FLED1];
>> +		max_flash_curr[FLED2] = cfg->iout_flash[FLED2];
>> +	}
>> +
>> +	for (i = first_led; i <= last_led; ++i) {
>> +		ret = max77693_set_flash_current(led, i,
>> +					max_flash_curr[i]);
>> +		if (ret < 0)
>> +			return ret;
>> +	}
>> +
>> +	v = TORCH_TMR_NO_TIMER | MAX77693_LED_TRIG_TYPE_LEVEL;
>> +	ret = regmap_write(rmap, MAX77693_LED_REG_ITORCHTIMER, v);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	/* initially set FLED1 timeout */
>> +	ret = max77693_set_timeout(led, cfg->flash_timeout[FLED1]);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	if (cfg->low_vsys > 0)
>> +		v = max77693_led_vsys_to_reg(cfg->low_vsys) |
>> +						MAX_FLASH1_MAX_FL_EN;
>> +	else
>> +		v = 0;
>> +
>> +	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH1, v);
>> +	if (ret < 0)
>> +		return ret;
>> +	ret = regmap_write(rmap, MAX77693_LED_REG_MAX_FLASH2, 0);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	if (cfg->boost_mode == MAX77693_LED_BOOST_FIXED)
>> +		v = FLASH_BOOST_FIXED;
>> +	else
>> +		v = cfg->boost_mode | cfg->boost_mode << 1;
>> +
>> +	if (max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))
>> +		v |= FLASH_BOOST_LEDNUM_2;
>> +
>> +	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_CNTL, v);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	v = max77693_led_vout_to_reg(cfg->boost_vout);
>> +	ret = regmap_write(rmap, MAX77693_LED_REG_VOUT_FLASH1, v);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	/* Allow all modes on both fled outputs */
>> +	led->allowed_modes = MODE_FLASH_MASK | MODE_TORCH_MASK;
>> +
>> +	return max77693_set_mode(led, MODE_OFF);
>> +}
>> +
>> +static int __max77693_led_brightness_set(struct max77693_led_device *led,
>> +					int fled_id, enum led_brightness value)
>> +{
>> +	int ret;
>> +
>> +	mutex_lock(&led->lock);
>> +
>> +	if (value == 0) {
>> +		ret = max77693_clear_mode(led, MODE_TORCH(fled_id));
>> +		if (ret < 0)
>> +			dev_dbg(&led->pdev->dev,
>> +				"Failed to clear torch mode (%d)\n",
>> +				ret);
>> +		goto unlock;
>> +	}
>> +
>> +	ret = max77693_set_torch_current(led, fled_id, value * TORCH_IOUT_STEP);
>> +	if (ret < 0) {
>> +		dev_dbg(&led->pdev->dev,
>> +			"Failed to set torch current (%d)\n",
>> +			ret);
>> +		goto unlock;
>> +	}
>> +
>> +	ret = max77693_add_mode(led, MODE_TORCH(fled_id));
>> +	if (ret < 0)
>> +		dev_dbg(&led->pdev->dev,
>> +			"Failed to set torch mode (%d)\n",
>> +			ret);
>> +unlock:
>> +	mutex_unlock(&led->lock);
>> +	return ret;
>> +}
>> +
>> +static void max77693_led_brightness_set_work(
>> +					struct work_struct *work)
>> +{
>> +	struct max77693_sub_led *sub_led =
>> +			container_of(work, struct max77693_sub_led,
>> +					work_brightness_set);
>> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
>> +
>> +	__max77693_led_brightness_set(led, sub_led->fled_id,
>> +				sub_led->torch_brightness);
>> +}
>> +
>> +/* LED subsystem callbacks */
>> +
>> +static int max77693_led_brightness_set_sync(
>> +				struct led_classdev *led_cdev,
>> +				enum led_brightness value)
>> +{
>> +	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
>> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
>> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
>> +
>> +	return __max77693_led_brightness_set(led, sub_led->fled_id, value);
>> +}
>> +
>> +static void max77693_led_brightness_set(
>> +				struct led_classdev *led_cdev,
>> +				enum led_brightness value)
>> +{
>> +	struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
>> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
>> +
>> +	sub_led->torch_brightness = value;
>> +	schedule_work(&sub_led->work_brightness_set);
>> +}
>> +
>> +static int max77693_led_flash_brightness_set(
>> +				struct led_classdev_flash *fled_cdev,
>> +				u32 brightness)
>> +{
>> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
>> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
>> +	int ret;
>> +
>> +	mutex_lock(&led->lock);
>> +	ret = max77693_set_flash_current(led, sub_led->fled_id, brightness);
>> +	mutex_unlock(&led->lock);
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77693_led_flash_strobe_set(
>> +				struct led_classdev_flash *fled_cdev,
>> +				bool state)
>> +{
>> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(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 (!state) {
>> +		ret = max77693_clear_mode(led, MODE_FLASH(fled_id));
>> +		goto unlock;
>> +	}
>> +
>> +	if (sub_led->flash_timeout != led->current_flash_timeout) {
>> +		ret = max77693_set_timeout(led, sub_led->flash_timeout);
>> +		if (ret < 0)
>> +			goto unlock;
>> +	}
>> +
>> +	led->strobing_sub_led_id = fled_id;
>> +
>> +	ret = max77693_add_mode(led, MODE_FLASH(fled_id));
>> +
>> +unlock:
>> +	mutex_unlock(&led->lock);
>> +	return ret;
>> +}
>> +
>> +static int max77693_led_flash_fault_get(
>> +				struct led_classdev_flash *fled_cdev,
>> +				u32 *fault)
>> +{
>> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
>> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
>> +	unsigned int v;
>> +	int ret;
>> +
>> +	ret = max77693_int_flag_get(led, &v);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	*fault = 0;
>> +
>> +	if (v & ((sub_led->fled_id == FLED1) ? FLASH_INT_FLED1_OPEN :
>> +					       FLASH_INT_FLED2_OPEN))
>> +		*fault |= LED_FAULT_OVER_VOLTAGE;
>> +	if (v & ((sub_led->fled_id == FLED1) ? FLASH_INT_FLED1_SHORT :
>> +					       FLASH_INT_FLED2_SHORT))
>> +		*fault |= LED_FAULT_SHORT_CIRCUIT;
>> +	if (v & FLASH_INT_OVER_CURRENT)
>> +		*fault |= LED_FAULT_OVER_CURRENT;
>> +
>> +	return 0;
>> +}
>> +
>> +static int max77693_led_flash_strobe_get(
>> +				struct led_classdev_flash *fled_cdev,
>> +				bool *state)
>> +{
>> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
>> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
>> +	int ret;
>> +
>> +	if (!state)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&led->lock);
>> +
>> +	ret = max77693_strobe_status_get(led, state);
>> +
>> +	*state = !!(*state && (led->strobing_sub_led_id == sub_led->fled_id));
>> +
>> +
>> +	mutex_unlock(&led->lock);
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77693_led_flash_timeout_set(
>> +				struct led_classdev_flash *fled_cdev,
>> +				u32 timeout)
>> +{
>> +	struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
>> +	struct max77693_led_device *led = sub_led_to_led(sub_led);
>> +
>> +	mutex_lock(&led->lock);
>> +	sub_led->flash_timeout = timeout;
>> +	mutex_unlock(&led->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int max77693_led_parse_dt(struct max77693_led_device *led,
>> +				 struct device_node *node)
>> +{
>> +	struct max77693_led_config_data *cfg = led->cfg_data;
>> +	struct max77693_sub_led *sub_leds = led->sub_leds;
>> +	struct device *dev = &led->pdev->dev;
>> +	struct device_node *child_node;
>> +	u32 led_sources[2];
>> +	int fled_id, ret;
>> +
>> +	of_property_read_u32(node, "maxim,trigger-type", &cfg->trigger_type);
>> +	of_property_read_u32(node, "maxim,boost-mode", &cfg->boost_mode);
>> +	of_property_read_u32(node, "maxim,boost-vout", &cfg->boost_vout);
>> +	of_property_read_u32(node, "maxim,vsys-min", &cfg->low_vsys);
>> +
>> +	for_each_available_child_of_node(node, child_node) {
>> +		ret = of_property_read_u32_array(child_node, "led-sources",
>> +							led_sources, 2);
>> +		if (ret < 0) {
>> +			dev_err(dev,
>> +				"Error reading \"led-sources\" DT property\n");
>> +			return ret;
>> +		}
>> +
>> +		if (led_sources[0] && led_sources[1]) {
>> +			fled_id = FLED1;
>> +			led->fled_mask = FLED1_IOUT | FLED2_IOUT;
>> +		} else if (led_sources[0] && !led_sources[1]) {
>> +			fled_id = FLED1;
>> +			led->fled_mask |= FLED1_IOUT;
>> +		} else if (!led_sources[0] && led_sources[1]) {
>> +			fled_id = FLED2;
>> +			led->fled_mask |= FLED2_IOUT;
>> +		} else {
>> +			dev_err(dev,
>> +				"Wrong \"led-sources\" DT property value\n");
>> +			return -EINVAL;
>> +		}
>> +
>> +		sub_leds[fled_id].fled_id = fled_id;
>> +
>> +		ret = of_property_read_string(child_node, "label",
>> +					(const char **) &cfg->label[fled_id]);
>> +		if (ret < 0) {
>> +			dev_err(dev, "Error reading \"label\" DT property\n");
>> +			return ret;
>> +		}
>> +
>> +		of_property_read_u32(child_node, "max-microamp",
>> +						&cfg->iout_torch[fled_id]);
>> +		of_property_read_u32(child_node, "flash-max-microamp",
>> +						&cfg->iout_flash[fled_id]);
>> +		of_property_read_u32(child_node, "flash-timeout-us",
>> +						&cfg->flash_timeout[fled_id]);
>> +
>> +		if (++led->cfg_data->num_leds == 2 ||
>> +		    (max77693_fled_used(led, FLED1) &&
>> +		     max77693_fled_used(led, FLED2)))
>> +			break;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void clamp_align(u32 *v, u32 min, u32 max, u32 step)
>> +{
>> +	*v = clamp_val(*v, min, max);
>> +	if (step > 1)
>> +		*v = (*v - min) / step * step + min;
>> +}
>> +
>> +static void max77693_led_validate_configuration(struct max77693_led_device *led)
>> +{
>> +	struct max77693_led_config_data *cfg = led->cfg_data;
>> +	int i;
>> +
>> +	if (led->cfg_data->num_leds == 1 &&
>> +	    max77693_fled_used(led, FLED1) && max77693_fled_used(led, FLED2))
>> +		led->iout_joint = true;
>> +
>> +	cfg->boost_mode = clamp_val(cfg->boost_mode, MAX77693_LED_BOOST_NONE,
>> +			    MAX77693_LED_BOOST_FIXED);
>> +
>> +	/* Boost must be enabled if both current outputs are used */
>> +	if ((cfg->boost_mode == MAX77693_LED_BOOST_NONE) && led->iout_joint)
>> +		cfg->boost_mode = MAX77693_LED_BOOST_FIXED;
>> +
>> +	/* Split max current settings to both outputs in case of joint leds */
>> +	if (led->iout_joint) {
>> +		cfg->iout_torch[FLED1] /= 2;
>> +		cfg->iout_torch[FLED2] = cfg->iout_torch[FLED1];
>> +		cfg->iout_flash[FLED1] /= 2;
>> +		cfg->iout_flash[FLED2] = cfg->iout_flash[FLED1];
>> +	}
>> +
>> +	for (i = FLED1; i <= FLED2; ++i) {
>> +		if (max77693_fled_used(led, i)) {
>> +			clamp_align(&cfg->iout_torch[i], TORCH_IOUT_MIN,
>> +					TORCH_IOUT_MAX, TORCH_IOUT_STEP);
>> +			clamp_align(&cfg->iout_flash[i], FLASH_IOUT_MIN,
>> +					cfg->boost_mode ? FLASH_IOUT_MAX_2LEDS :
>> +							FLASH_IOUT_MAX_1LED,
>> +					FLASH_IOUT_STEP);
>> +		} else {
>> +			cfg->iout_torch[i] = cfg->iout_flash[i] = 0;
>> +		}
>> +	}
>> +
>> +	for (i = 0; i < ARRAY_SIZE(cfg->flash_timeout); ++i)
>> +		clamp_align(&cfg->flash_timeout[i], FLASH_TIMEOUT_MIN,
>> +				FLASH_TIMEOUT_MAX, FLASH_TIMEOUT_STEP);
>> +
>> +	cfg->trigger_type = clamp_val(cfg->trigger_type,
>> +					MAX77693_LED_TRIG_TYPE_EDGE,
>> +					MAX77693_LED_TRIG_TYPE_LEVEL);
>> +
>> +	clamp_align(&cfg->boost_vout, FLASH_VOUT_MIN, FLASH_VOUT_MAX,
>> +							FLASH_VOUT_STEP);
>> +
>> +	if (cfg->low_vsys)
>> +		clamp_align(&cfg->low_vsys, MAX_FLASH1_VSYS_MIN,
>> +				MAX_FLASH1_VSYS_MAX, MAX_FLASH1_VSYS_STEP);
>> +}
>> +
>> +static int max77693_led_get_configuration(struct max77693_led_device *led)
>> +{
>> +	struct device *dev = &led->pdev->dev;
>> +	int ret;
>> +
>> +	if (!dev->of_node)
>> +		return -EINVAL;
>> +
>> +	led->cfg_data = devm_kzalloc(dev, sizeof(*led->cfg_data), GFP_KERNEL);
>> +	if (!led->cfg_data)
>> +		return -ENOMEM;
>> +
>> +	ret = max77693_led_parse_dt(led, dev->of_node);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	max77693_led_validate_configuration(led);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct led_flash_ops flash_ops = {
>> +	.flash_brightness_set	= max77693_led_flash_brightness_set,
>> +	.strobe_set		= max77693_led_flash_strobe_set,
>> +	.strobe_get		= max77693_led_flash_strobe_get,
>> +	.timeout_set		= max77693_led_flash_timeout_set,
>> +	.fault_get		= max77693_led_flash_fault_get,
>> +};
>> +
>> +static void max77693_init_flash_settings(struct max77693_led_device *led,
>> +					 struct max77693_led_settings *s,
>> +					 int fled_id)
>> +{
>> +	struct max77693_led_config_data *cfg = led->cfg_data;
>> +	struct led_flash_setting *setting;
>> +
>> +	/* Init torch intensity setting */
>> +	setting = &s->torch_brightness;
>> +	setting->min = TORCH_IOUT_MIN;
>> +	setting->max = cfg->iout_torch[fled_id];
>> +	setting->max = led->iout_joint ?
>> +			cfg->iout_torch[FLED1] + cfg->iout_torch[FLED2] :
>> +			cfg->iout_torch[fled_id];
>> +	setting->step = TORCH_IOUT_STEP;
>> +	setting->val = setting->max;
>> +
>> +	/* Init flash intensity setting */
>> +	setting = &s->flash_brightness;
>> +	setting->min = FLASH_IOUT_MIN;
>> +	setting->max = led->iout_joint ?
>> +			cfg->iout_flash[FLED1] + cfg->iout_flash[FLED2] :
>> +			cfg->iout_flash[fled_id];
>> +	setting->step = FLASH_IOUT_STEP;
>> +	setting->val = setting->max;
>> +
>> +	/* Init flash timeout setting */
>> +	setting = &s->flash_timeout;
>> +	setting->min = FLASH_TIMEOUT_MIN;
>> +	setting->max = cfg->flash_timeout[fled_id];
>> +	setting->step = FLASH_TIMEOUT_STEP;
>> +	setting->val = setting->max;
>> +}
>> +
>> +static int max77693_set_available_sync_led(struct max77693_led_device *led,
>> +						int fled_id)
>> +{
>> +	struct max77693_sub_led *sub_led = &led->sub_leds[fled_id];
>> +	struct led_classdev_flash *fled_cdev = &sub_led->fled_cdev;
>> +
>> +	fled_cdev->sync_leds = devm_kzalloc(&led->pdev->dev, sizeof(fled_cdev),
>> +					GFP_KERNEL);
>> +	if (!fled_cdev->sync_leds)
>> +		return -ENOMEM;
>> +
>> +	fled_cdev->sync_leds[0] = &led->sub_leds[!fled_id].fled_cdev;
>> +	fled_cdev->num_sync_leds = 1;
>> +
>> +	return 0;
>> +}
>> +
>> +static void max77693_init_fled_cdev(struct max77693_led_device *led,
>> +					int fled_id)
>> +{
>> +	struct led_classdev_flash *fled_cdev;
>> +	struct led_classdev *led_cdev;
>> +	struct max77693_sub_led *sub_led = &led->sub_leds[fled_id];
>> +	struct max77693_led_settings settings;
>> +
>> +	/* Initialize flash settings */
>> +	max77693_init_flash_settings(led, &settings, fled_id);
>> +
>> +	/* Initialize LED Flash class device */
>> +	fled_cdev = &sub_led->fled_cdev;
>> +	fled_cdev->ops = &flash_ops;
>> +	led_cdev = &fled_cdev->led_cdev;
>> +	led_cdev->name = led->cfg_data->label[fled_id];
>> +	led_cdev->brightness_set = max77693_led_brightness_set;
>> +	led_cdev->brightness_set_sync = max77693_led_brightness_set_sync;
>> +	INIT_WORK(&sub_led->work_brightness_set,
>> +			max77693_led_brightness_set_work);
>> +
>> +	led_cdev->max_brightness = settings.torch_brightness.val /
>> +					TORCH_IOUT_STEP;
>> +	led_cdev->flags |= LED_DEV_CAP_FLASH;
>> +	if (led->cfg_data->num_leds == 2)
>> +		led_cdev->flags |= LED_DEV_CAP_SYNC_STROBE;
>> +
>> +	fled_cdev->brightness = settings.flash_brightness;
>> +	fled_cdev->timeout = settings.flash_timeout;
>> +	sub_led->flash_timeout = fled_cdev->timeout.val;
>> +}
>> +
>> +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;
>> +	int init_fled_cdev[2], i, ret;
>> +
>> +	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
>> +	if (!led)
>> +		return -ENOMEM;
>> +
>> +	led->pdev = pdev;
>> +	led->regmap = iodev->regmap;
>> +	sub_leds = led->sub_leds;
>> +
>> +	platform_set_drvdata(pdev, led);
>> +	ret = max77693_led_get_configuration(led);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	ret = max77693_setup(led);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	init_fled_cdev[FLED1] =
>> +			led->iout_joint || max77693_fled_used(led, FLED1);
>> +	init_fled_cdev[FLED2] =
>> +			!led->iout_joint && max77693_fled_used(led, FLED2);
>> +
>> +	/* Initialize LED Flash class device(s) */
>> +	for (i = FLED1; i <= FLED2; ++i)
>> +		if (init_fled_cdev[i])
>> +			max77693_init_fled_cdev(led, i);
>> +
>> +	/* Setup sub-leds available for flash strobe synchronization */
>> +	if (led->cfg_data->num_leds == 2) {
>> +		for (i = FLED1; i <= FLED2; ++i) {
>> +			ret = max77693_set_available_sync_led(led, i);
>> +			if (ret < 0)
>> +				return ret;
>> +		}
>> +	}
>> +
>> +	mutex_init(&led->lock);
>> +
>> +	/* Register LED Flash class device(s) */
>> +	for (i = FLED1; i <= FLED2; ++i) {
>> +		if (init_fled_cdev[i]) {
>
> if (!...)
> 	continue;
>
> The rest of the loop would look nicer this way I think. Up to you.

Right.

>> +			ret = led_classdev_flash_register(dev,
>> +							&sub_leds[i].fled_cdev);
>> +			if (ret < 0) {
>> +				/*
>> +				 * At this moment FLED1 might have been already
>> +				 * registered and it needs to be released.
>> +				 */
>> +				if (i == FLED2)
>> +					goto err_register_led2;
>> +				else
>> +					goto err_register_led1;
>> +			}
>> +		}
>> +	}
>> +
>> +
>> +	return 0;
>> +
>> +err_register_led2:
>> +	/* It is possible than only FLED2 was to be registered */
>> +	if (!init_fled_cdev[FLED1])
>> +		goto err_register_led1;
>> +	led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
>> +err_register_led1:
>> +	mutex_destroy(&led->lock);
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77693_led_remove(struct platform_device *pdev)
>> +{
>> +	struct max77693_led_device *led = platform_get_drvdata(pdev);
>> +	struct max77693_sub_led *sub_leds = led->sub_leds;
>> +
>> +	if (led->iout_joint || max77693_fled_used(led, FLED1)) {
>> +		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)) {
>> +		led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);
>> +		cancel_work_sync(&sub_leds[FLED2].work_brightness_set);
>> +	}
>> +
>> +	mutex_destroy(&led->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct of_device_id max77693_led_dt_match[] = {
>> +	{.compatible = "maxim,max77693-led"},
>> +	{},
>> +};
>> +
>> +static struct platform_driver max77693_led_driver = {
>> +	.probe		= max77693_led_probe,
>> +	.remove		= max77693_led_remove,
>> +	.driver		= {
>> +		.name	= "max77693-led",
>> +		.owner	= THIS_MODULE,
>> +		.of_match_table = max77693_led_dt_match,
>> +	},
>> +};
>> +
>> +module_platform_driver(max77693_led_driver);
>> +
>> +MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
>> +MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
>> +MODULE_DESCRIPTION("Maxim MAX77693 led flash driver");
>> +MODULE_LICENSE("GPL v2");
>


-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 14/19] v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control
  2015-01-09 15:23 ` [PATCH/RFC v10 14/19] v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control Jacek Anaszewski
       [not found]   ` <1420816989-1808-15-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2015-02-05 16:36   ` Sakari Ailus
  1 sibling, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2015-02-05 16:36 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, s.nawrocki, Hans Verkuil

On Fri, Jan 09, 2015 at 04:23:04PM +0100, Jacek Anaszewski wrote:
> Add V4L2_CID_FLASH_SYNC_STROBE control for determining
> whether a flash device strobe has to be synchronized
> with other flash leds controller by the same device.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Sakari Ailus <sakari.ailus@iki.fi>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Thanks!

Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices
  2015-01-09 15:23 ` [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices Jacek Anaszewski
  2015-01-09 20:54   ` Pavel Machek
@ 2015-02-05 17:59   ` Sakari Ailus
  2015-02-09 11:15     ` Jacek Anaszewski
  1 sibling, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2015-02-05 17:59 UTC (permalink / raw)
  To: Jacek Anaszewski
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, s.nawrocki, Hans Verkuil

Hi Jacek,

Thank you for your continuous efforts on this! I think this ended up being
more complicated than I originally anticipated.

On Fri, Jan 09, 2015 at 04:23:05PM +0100, Jacek Anaszewski wrote:
> This patch adds helper functions for registering/unregistering
> LED Flash class devices as V4L2 sub-devices. The functions should
> be called from the LED subsystem device driver. In case the
> support for V4L2 Flash sub-devices is disabled in the kernel
> config the functions' empty versions will be used.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Sakari Ailus <sakari.ailus@iki.fi>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  drivers/media/v4l2-core/Kconfig      |   11 +
>  drivers/media/v4l2-core/Makefile     |    2 +
>  drivers/media/v4l2-core/v4l2-flash.c |  581 ++++++++++++++++++++++++++++++++++
>  include/media/v4l2-flash.h           |  139 ++++++++
>  4 files changed, 733 insertions(+)
>  create mode 100644 drivers/media/v4l2-core/v4l2-flash.c
>  create mode 100644 include/media/v4l2-flash.h
> 
> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
> index ba7e21a..f034f1a 100644
> --- a/drivers/media/v4l2-core/Kconfig
> +++ b/drivers/media/v4l2-core/Kconfig
> @@ -44,6 +44,17 @@ config V4L2_MEM2MEM_DEV
>          tristate
>          depends on VIDEOBUF2_CORE
>  
> +# Used by LED subsystem flash drivers
> +config V4L2_FLASH_LED_CLASS
> +	tristate "Enable support for Flash sub-devices"
> +	depends on VIDEO_V4L2_SUBDEV_API
> +	depends on LEDS_CLASS_FLASH
> +	---help---
> +	  Say Y here to enable support for Flash sub-devices, which allow
> +	  to control LED class devices with use of V4L2 Flash controls.
> +
> +	  When in doubt, say N.
> +
>  # Used by drivers that need Videobuf modules
>  config VIDEOBUF_GEN
>  	tristate
> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
> index 63d29f2..44e858c 100644
> --- a/drivers/media/v4l2-core/Makefile
> +++ b/drivers/media/v4l2-core/Makefile
> @@ -22,6 +22,8 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
>  
>  obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
>  
> +obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash.o
> +
>  obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
>  obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
>  obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
> diff --git a/drivers/media/v4l2-core/v4l2-flash.c b/drivers/media/v4l2-core/v4l2-flash.c
> new file mode 100644
> index 0000000..3fd6a08
> --- /dev/null
> +++ b/drivers/media/v4l2-core/v4l2-flash.c
> @@ -0,0 +1,581 @@
> +/*
> + * V4L2 Flash LED sub-device registration helpers.
> + *
> + *	Copyright (C) 2015 Samsung Electronics Co., Ltd
> + *	Author: Jacek Anaszewski <j.anaszewski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation."
> + */
> +
> +#include <linux/led-class-flash.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <media/v4l2-flash.h>
> +
> +#define has_flash_op(v4l2_flash, op)			\
> +	(v4l2_flash && v4l2_flash->ops->op)
> +
> +#define call_flash_op(v4l2_flash, op, args...)		\
> +		(has_flash_op(v4l2_flash, op) ?		\
> +			v4l2_flash->ops->op(args) :	\

Wouldn't you need __VA_ARGS__ here to deliver the variable argument to the
callee? Do you need variable arguments for the current flash ops?

> +			-EINVAL)
> +
> +static inline enum led_brightness v4l2_flash_intensity_to_led_brightness(

I'd drop inline and let the compiler decide. Same below.

> +					struct v4l2_ctrl **ctrls,
> +					enum ctrl_init_data_id cdata_id,
> +					s32 intensity)
> +{
> +	struct v4l2_ctrl *ctrl = ctrls[cdata_id];
> +	s64 __intensity = intensity - ctrl->minimum;
> +
> +	do_div(__intensity, ctrl->step);
> +
> +	/*
> +	 * Indicator leds, unlike torch leds, are turned on/off basing on
> +	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
> +	 * Therefore it must be possible to set it to 0 level which in
> +	 * the LED subsystem reflects LED_OFF state.
> +	 */
> +	if (cdata_id != INDICATOR_INTENSITY)
> +		++__intensity;
> +
> +	return __intensity;
> +}
> +
> +static inline s32 v4l2_flash_led_brightness_to_intensity(
> +					struct v4l2_ctrl **ctrls,
> +					enum ctrl_init_data_id cdata_id,

Could you pass a pointer to struct v4l2_ctrl instead?

> +					enum led_brightness brightness)
> +{
> +	struct v4l2_ctrl *ctrl = ctrls[cdata_id];
> +
> +	/*
> +	 * Indicator leds, unlike torch leds, are turned on/off basing on
> +	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
> +	 * Do not decrement brightness read from the LED subsystem for
> +	 * indicator led as it may equal 0. For torch leds this function
> +	 * is called only when V4L2_FLASH_LED_MODE_TORCH is set and the
> +	 * brightness read is guaranteed to be greater than 0. In the mode
> +	 * V4L2_FLASH_LED_MODE_NONE the cached torch intensity value is used.
> +	 */
> +	if (cdata_id != INDICATOR_INTENSITY)
> +		--brightness;
> +
> +	return (brightness * ctrl->step) + ctrl->minimum;
> +}
> +
> +static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c)
> +{
> +	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 v4l2_ctrl **ctrls = v4l2_flash->ctrls;
> +	bool is_strobing;
> +	int ret;
> +
> +	switch (c->id) {
> +	case V4L2_CID_FLASH_TORCH_INTENSITY:
> +		/*
> +		 * Update torch brightness only if in TORCH_MODE.
> +		 * In other modes torch led is turned off, which
> +		 * would spuriously inform the user space that
> +		 * V4L2_CID_FLASH_TORCH_INTENSITY control setting
> +		 * has changed.
> +		 */
> +		if (ctrls[LED_MODE]->val == V4L2_FLASH_LED_MODE_TORCH) {
> +			ret = led_update_brightness(led_cdev);
> +			if (ret < 0)
> +				return ret;
> +			c->val = v4l2_flash_led_brightness_to_intensity(
> +							ctrls, TORCH_INTENSITY,
> +							led_cdev->brightness);
> +		}
> +		return 0;
> +	case V4L2_CID_FLASH_INDICATOR_INTENSITY:
> +		ret = led_update_brightness(led_cdev);
> +		if (ret < 0)
> +			return ret;
> +		c->val = v4l2_flash_led_brightness_to_intensity(
> +						ctrls, INDICATOR_INTENSITY,
> +						led_cdev->brightness);
> +		return 0;
> +	case V4L2_CID_FLASH_INTENSITY:
> +		ret = led_update_flash_brightness(fled_cdev);
> +		if (ret < 0)
> +			return ret;
> +		/* no conversion is needed */
> +		c->val = fled_cdev->brightness.val;
> +		return 0;
> +	case V4L2_CID_FLASH_STROBE_STATUS:
> +		ret = led_get_flash_strobe(fled_cdev, &is_strobing);
> +		if (ret < 0)
> +			return ret;
> +		c->val = is_strobing;
> +		return 0;
> +	case V4L2_CID_FLASH_FAULT:
> +		/* led faults map directly to V4L2 flash faults */
> +		return led_get_flash_fault(fled_cdev, &c->val);
> +	case V4L2_CID_FLASH_SYNC_STROBE:
> +		c->val = fled_cdev->sync_led_id;
> +		return 0;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
> +{
> +	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 v4l2_ctrl **ctrls = v4l2_flash->ctrls;
> +	enum led_brightness brightness;
> +	bool external_strobe;
> +	int ret = 0;
> +
> +	switch (c->id) {
> +	case V4L2_CID_FLASH_LED_MODE:
> +		switch (c->val) {
> +		case V4L2_FLASH_LED_MODE_NONE:
> +			led_set_brightness(led_cdev, LED_OFF);
> +			return led_set_flash_strobe(fled_cdev, false);
> +		case V4L2_FLASH_LED_MODE_FLASH:
> +			/* Turn the torch LED off */
> +			led_set_brightness(led_cdev, LED_OFF);
> +			external_strobe = (ctrls[STROBE_SOURCE]->val ==
> +					V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
> +
> +			if (has_flash_op(v4l2_flash, external_strobe_set))
> +				ret = call_flash_op(v4l2_flash,
> +						external_strobe_set, v4l2_flash,
> +						external_strobe);
> +			return ret;
> +		case V4L2_FLASH_LED_MODE_TORCH:
> +			/* Stop flash strobing */
> +			ret = led_set_flash_strobe(fled_cdev, false);
> +			if (ret < 0)
> +				return ret;
> +
> +			brightness =
> +				v4l2_flash_intensity_to_led_brightness(
> +						ctrls, TORCH_INTENSITY,
> +						ctrls[TORCH_INTENSITY]->val);
> +			led_set_brightness(led_cdev, brightness);
> +			return 0;
> +		}
> +		break;
> +	case V4L2_CID_FLASH_STROBE_SOURCE:
> +		external_strobe = (c->val == V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
> +
> +		return call_flash_op(v4l2_flash, external_strobe_set,
> +					v4l2_flash, external_strobe);
> +	case V4L2_CID_FLASH_STROBE:
> +		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH ||
> +		    ctrls[STROBE_SOURCE]->val !=
> +					V4L2_FLASH_STROBE_SOURCE_SOFTWARE)
> +			return -EINVAL;
> +		return led_set_flash_strobe(fled_cdev, true);
> +	case V4L2_CID_FLASH_STROBE_STOP:
> +		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH ||
> +		    ctrls[STROBE_SOURCE]->val !=
> +					V4L2_FLASH_STROBE_SOURCE_SOFTWARE)
> +			return -EINVAL;
> +		return led_set_flash_strobe(fled_cdev, false);
> +	case V4L2_CID_FLASH_TIMEOUT:
> +		/* no conversion is needed */
> +		return led_set_flash_timeout(fled_cdev, c->val);
> +	case V4L2_CID_FLASH_INTENSITY:
> +		/* no conversion is needed */
> +		return led_set_flash_brightness(fled_cdev, c->val);
> +	case V4L2_CID_FLASH_INDICATOR_INTENSITY:
> +		brightness = v4l2_flash_intensity_to_led_brightness(
> +						ctrls, INDICATOR_INTENSITY,
> +						c->val);
> +		led_set_brightness(led_cdev, brightness);
> +		return 0;
> +	case V4L2_CID_FLASH_TORCH_INTENSITY:
> +		/*
> +		 * If not in MODE_TORCH don't call led-class brightness_set
> +		 * op, as it would result in turning the torch led on.
> +		 * Instead the value is cached only and will be written
> +		 * to the device upon transition to MODE_TORCH.
> +		 */
> +		if (ctrls[LED_MODE]->val == V4L2_FLASH_LED_MODE_TORCH) {
> +			brightness =
> +				v4l2_flash_intensity_to_led_brightness(
> +							ctrls, TORCH_INTENSITY,
> +							c->val);
> +			led_set_brightness(led_cdev, brightness);
> +		}
> +		return 0;
> +	case V4L2_CID_FLASH_SYNC_STROBE:
> +		fled_cdev->sync_led_id = c->val;
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops = {
> +	.g_volatile_ctrl = v4l2_flash_g_volatile_ctrl,
> +	.s_ctrl = v4l2_flash_s_ctrl,
> +};
> +
> +static void fill_ctrl_init_data(struct v4l2_flash *v4l2_flash,
> +			  struct v4l2_flash_ctrl_config *flash_ctrl_cfg,
> +			  struct v4l2_flash_ctrl_data *ctrl_init_data)
> +{
> +	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
> +	const struct led_flash_ops *fled_cdev_ops = fled_cdev->ops;
> +	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
> +	struct v4l2_ctrl_config *ctrl_cfg;
> +	u32 mask;
> +	s64 max;
> +
> +	/* Init FLASH_FAULT ctrl data */
> +	if (flash_ctrl_cfg->flash_faults) {
> +		ctrl_init_data[FLASH_FAULT].supported = true;
> +		ctrl_cfg = &ctrl_init_data[FLASH_FAULT].config;
> +		ctrl_cfg->id = V4L2_CID_FLASH_FAULT;
> +		ctrl_cfg->max = flash_ctrl_cfg->flash_faults;
> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
> +				  V4L2_CTRL_FLAG_READ_ONLY;
> +	}
> +
> +	/* Init INDICATOR_INTENSITY ctrl data */
> +	if (flash_ctrl_cfg->indicator_led) {
> +		ctrl_init_data[INDICATOR_INTENSITY].supported = true;
> +		ctrl_init_data[INDICATOR_INTENSITY].config =
> +						flash_ctrl_cfg->intensity;
> +		ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config;
> +		ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
> +		ctrl_cfg->min = 0;
> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
> +
> +		/* Indicator LED can have only faults and intensity controls. */
> +		return;
> +	}
> +
> +	/* Init FLASH_LED_MODE ctrl data */
> +	mask = 1 << V4L2_FLASH_LED_MODE_NONE |
> +	       1 << V4L2_FLASH_LED_MODE_TORCH;
> +	if (led_cdev->flags & LED_DEV_CAP_FLASH)
> +		mask |= 1 << V4L2_FLASH_LED_MODE_FLASH;
> +
> +	ctrl_init_data[LED_MODE].supported = true;
> +	ctrl_cfg = &ctrl_init_data[LED_MODE].config;
> +	ctrl_cfg->id = V4L2_CID_FLASH_LED_MODE;
> +	ctrl_cfg->max = V4L2_FLASH_LED_MODE_TORCH;
> +	ctrl_cfg->menu_skip_mask = ~mask;
> +	ctrl_cfg->def = V4L2_FLASH_LED_MODE_NONE;
> +	ctrl_cfg->flags = 0;
> +
> +	/* Init TORCH_INTENSITY ctrl data */
> +	ctrl_init_data[TORCH_INTENSITY].supported = true;
> +	ctrl_init_data[TORCH_INTENSITY].config = flash_ctrl_cfg->intensity;
> +	ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config;
> +	ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY;
> +	ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
> +
> +	if (!(led_cdev->flags & LED_DEV_CAP_FLASH))
> +		return;
> +
> +	/* Init FLASH_STROBE_SOURCE ctrl data */
> +	mask = 1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
> +	if (flash_ctrl_cfg->has_external_strobe) {
> +		mask |= 1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
> +		max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
> +	} else {
> +		max = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
> +	}
> +
> +	ctrl_init_data[STROBE_SOURCE].supported = true;
> +	ctrl_cfg = &ctrl_init_data[STROBE_SOURCE].config;
> +	ctrl_cfg->id = V4L2_CID_FLASH_STROBE_SOURCE;
> +	ctrl_cfg->max = max;
> +	ctrl_cfg->menu_skip_mask = ~mask;
> +	ctrl_cfg->def = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
> +
> +	/* Init FLASH_STROBE ctrl data */
> +	ctrl_init_data[FLASH_STROBE].supported = true;
> +	ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config;
> +	ctrl_cfg->id = V4L2_CID_FLASH_STROBE;
> +
> +	/* Init STROBE_STOP ctrl data */
> +	ctrl_init_data[STROBE_STOP].supported = true;
> +	ctrl_cfg = &ctrl_init_data[STROBE_STOP].config;
> +	ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STOP;
> +
> +	/* Init STROBE_STATUS ctrl data */
> +	if (fled_cdev_ops->strobe_get) {
> +		ctrl_init_data[STROBE_STATUS].supported = true;
> +		ctrl_cfg = &ctrl_init_data[STROBE_STATUS].config;
> +		ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STATUS;
> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
> +				  V4L2_CTRL_FLAG_READ_ONLY;
> +	}
> +
> +	/* Init FLASH_TIMEOUT ctrl data */
> +	if (fled_cdev_ops->timeout_set) {
> +		ctrl_init_data[FLASH_TIMEOUT].supported = true;
> +		ctrl_init_data[FLASH_TIMEOUT].config =
> +					flash_ctrl_cfg->flash_timeout;
> +		ctrl_cfg = &ctrl_init_data[FLASH_TIMEOUT].config;
> +		ctrl_cfg->id = V4L2_CID_FLASH_TIMEOUT;
> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
> +	}
> +
> +	/* Init FLASH_INTENSITY ctrl data */
> +	if (fled_cdev_ops->flash_brightness_set) {
> +		ctrl_init_data[FLASH_INTENSITY].supported = true;
> +		ctrl_init_data[FLASH_INTENSITY].config =
> +					flash_ctrl_cfg->flash_intensity;
> +		ctrl_cfg = &ctrl_init_data[FLASH_INTENSITY].config;
> +		ctrl_cfg->id = V4L2_CID_FLASH_INTENSITY;
> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
> +	}
> +}
> +
> +static int v4l2_flash_init_sync_strobe_menu(struct v4l2_flash *v4l2_flash)
> +{
> +	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
> +	struct v4l2_ctrl *ctrl;
> +	int i = 0;
> +
> +	v4l2_flash->sync_strobe_menu =
> +			devm_kcalloc(fled_cdev->led_cdev.dev->parent,
> +					fled_cdev->num_sync_leds + 1,
> +					sizeof(*fled_cdev),
> +					GFP_KERNEL);
> +
> +	if (!v4l2_flash->sync_strobe_menu)
> +		return -ENOMEM;
> +
> +	v4l2_flash->sync_strobe_menu[0] = "none";
> +
> +	for (i = 0; i < fled_cdev->num_sync_leds; ++i)
> +		v4l2_flash->sync_strobe_menu[i + 1] =
> +				(char *) fled_cdev->sync_leds[i]->led_cdev.name;

What's here, and where does it come from?

The rest of the sub-devices typically have a device's (chip's) name and the
bus address (usually i2c).

> +	ctrl = v4l2_ctrl_new_std_menu_items(
> +		&v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
> +		V4L2_CID_FLASH_SYNC_STROBE,
> +		fled_cdev->num_sync_leds,
> +		0, 0,
> +		(const char * const *) v4l2_flash->sync_strobe_menu);

Do you need the casting here?

> +
> +	if (ctrl)
> +		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
> +
> +	return 0;
> +}
> +
> +static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash,
> +				struct v4l2_flash_ctrl_config *flash_ctrl_cfg)
> +
> +{
> +	struct led_classdev *led_cdev = &v4l2_flash->fled_cdev->led_cdev;
> +	struct v4l2_flash_ctrl_data *ctrl_init_data;
> +	struct v4l2_ctrl *ctrl;
> +	struct v4l2_ctrl_config *ctrl_cfg;
> +	int i, ret, num_ctrls = 0;
> +
> +	/* allocate memory dynamically so as not to exceed stack frame size */
> +	ctrl_init_data = kcalloc(NUM_FLASH_CTRLS, sizeof(*ctrl_init_data),
> +					GFP_KERNEL);
> +	if (!ctrl_init_data)
> +		return -ENOMEM;
> +
> +	memset(ctrl_init_data, 0, sizeof(*ctrl_init_data));

kcalloc() clears the memory, no need to do it again.

> +	fill_ctrl_init_data(v4l2_flash, flash_ctrl_cfg, ctrl_init_data);
> +
> +	for (i = 0; i < NUM_FLASH_CTRLS; ++i)
> +		if (ctrl_init_data[i].supported)
> +			++num_ctrls;
> +
> +	v4l2_ctrl_handler_init(&v4l2_flash->hdl, num_ctrls);
> +
> +	for (i = 0; i < NUM_FLASH_CTRLS; ++i) {
> +		ctrl_cfg = &ctrl_init_data[i].config;
> +		if (!ctrl_init_data[i].supported)
> +			continue;
> +
> +		if (ctrl_cfg->id == V4L2_CID_FLASH_LED_MODE ||
> +		    ctrl_cfg->id == V4L2_CID_FLASH_STROBE_SOURCE)
> +			ctrl = v4l2_ctrl_new_std_menu(&v4l2_flash->hdl,
> +						&v4l2_flash_ctrl_ops,
> +						ctrl_cfg->id,
> +						ctrl_cfg->max,
> +						ctrl_cfg->menu_skip_mask,
> +						ctrl_cfg->def);
> +		else
> +			ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl,
> +						&v4l2_flash_ctrl_ops,
> +						ctrl_cfg->id,
> +						ctrl_cfg->min,
> +						ctrl_cfg->max,
> +						ctrl_cfg->step,
> +						ctrl_cfg->def);
> +
> +		if (ctrl)
> +			ctrl->flags |= ctrl_cfg->flags;
> +
> +		if (i <= STROBE_SOURCE)
> +			v4l2_flash->ctrls[i] = ctrl;
> +	}
> +
> +	kfree(ctrl_init_data);
> +
> +	if (led_cdev->flags & LED_DEV_CAP_SYNC_STROBE) {
> +		ret = v4l2_flash_init_sync_strobe_menu(v4l2_flash);
> +		if (ret < 0)
> +			goto error_free_handler;
> +	}
> +
> +	if (v4l2_flash->hdl.error) {
> +		ret = v4l2_flash->hdl.error;
> +		goto error_free_handler;
> +	}
> +
> +	v4l2_ctrl_handler_setup(&v4l2_flash->hdl);
> +
> +	v4l2_flash->sd.ctrl_handler = &v4l2_flash->hdl;
> +
> +	return 0;
> +
> +error_free_handler:
> +	v4l2_ctrl_handler_free(&v4l2_flash->hdl);
> +	return ret;
> +}
> +
> +/*
> + * V4L2 subdev internal operations
> + */
> +
> +static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> +{
> +	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;
> +	int ret = 0;
> +
> +	mutex_lock(&led_cdev->led_access);
> +
> +	if (!v4l2_fh_is_singular(&fh->vfh)) {
> +		ret = -EBUSY;
> +		goto unlock;
> +	}
> +
> +	led_sysfs_disable(led_cdev);
> +
> +unlock:
> +	mutex_unlock(&led_cdev->led_access);
> +	return ret;
> +}
> +
> +static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> +{
> +	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;
> +	int ret = 0;
> +
> +	mutex_lock(&led_cdev->led_access);
> +
> +	if (has_flash_op(v4l2_flash, external_strobe_set))
> +		ret = call_flash_op(v4l2_flash, external_strobe_set,
> +				v4l2_flash, false);
> +	led_sysfs_enable(led_cdev);
> +
> +	mutex_unlock(&led_cdev->led_access);
> +
> +	return ret;
> +}
> +
> +static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = {
> +	.open = v4l2_flash_open,
> +	.close = v4l2_flash_close,
> +};
> +
> +static const struct v4l2_subdev_core_ops v4l2_flash_core_ops = {
> +	.queryctrl = v4l2_subdev_queryctrl,
> +	.querymenu = v4l2_subdev_querymenu,
> +};
> +
> +static const struct v4l2_subdev_ops v4l2_flash_subdev_ops = {
> +	.core = &v4l2_flash_core_ops,
> +};
> +
> +struct v4l2_flash *v4l2_flash_init(struct led_classdev_flash *fled_cdev,
> +				   const struct v4l2_flash_ops *ops,
> +				   struct v4l2_flash_ctrl_config *config)
> +{
> +	struct v4l2_flash *v4l2_flash;
> +	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
> +	struct v4l2_subdev *sd;
> +	int ret;
> +
> +	if (!fled_cdev || !ops || !config)
> +		return ERR_PTR(-EINVAL);
> +
> +	v4l2_flash = kzalloc(sizeof(*v4l2_flash), GFP_KERNEL);
> +	if (!v4l2_flash)
> +		return ERR_PTR(-ENOMEM);
> +
> +	sd = &v4l2_flash->sd;
> +	v4l2_flash->fled_cdev = fled_cdev;
> +	v4l2_flash->ops = ops;
> +	sd->dev = led_cdev->dev;
> +	v4l2_subdev_init(sd, &v4l2_flash_subdev_ops);
> +	sd->internal_ops = &v4l2_flash_subdev_internal_ops;
> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +	snprintf(sd->name, sizeof(sd->name), led_cdev->name);

strlcpy() or snprintf(sd->name, sizeof(), "%s", led_cdev->name).

> +
> +	ret = v4l2_flash_init_controls(v4l2_flash, config);
> +	if (ret < 0)
> +		goto err_init_controls;
> +
> +	ret = media_entity_init(&sd->entity, 0, NULL, 0);
> +	if (ret < 0)
> +		goto err_init_entity;
> +
> +	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
> +
> +	ret = v4l2_async_register_subdev(sd);
> +	if (ret < 0)
> +		goto err_init_entity;
> +
> +	return v4l2_flash;
> +
> +err_init_entity:
> +	media_entity_cleanup(&sd->entity);

media_entity_cleanup() can be called on an uninitialised entity (as long as
it's zeroed). So you could simplity this a little. Up to you.

> +err_init_controls:
> +	v4l2_ctrl_handler_free(sd->ctrl_handler);
> +	kfree(v4l2_flash);
> +
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_flash_init);
> +
> +void v4l2_flash_release(struct v4l2_flash *v4l2_flash)
> +{
> +	struct v4l2_subdev *sd = &v4l2_flash->sd;
> +
> +	if (!v4l2_flash)
> +		return;
> +
> +	v4l2_async_unregister_subdev(sd);
> +	media_entity_cleanup(&sd->entity);
> +	v4l2_ctrl_handler_free(sd->ctrl_handler);
> +	kfree(v4l2_flash);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_flash_release);
> +
> +MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
> +MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/media/v4l2-flash.h b/include/media/v4l2-flash.h
> new file mode 100644
> index 0000000..404b5a8
> --- /dev/null
> +++ b/include/media/v4l2-flash.h
> @@ -0,0 +1,139 @@
> +/*
> + * V4L2 Flash LED sub-device registration helpers.
> + *
> + *	Copyright (C) 2015 Samsung Electronics Co., Ltd
> + *	Author: Jacek Anaszewski <j.anaszewski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation."

There's an unbalanced quote here. Is that intended? Same in the .c file.

> + */
> +
> +#ifndef _V4L2_FLASH_H
> +#define _V4L2_FLASH_H
> +
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-dev.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-ioctl.h>

Do you need all the above headers here?

> +
> +struct led_classdev_flash;
> +struct led_classdev;
> +struct v4l2_flash;
> +enum led_brightness;
> +
> +enum ctrl_init_data_id {
> +	LED_MODE,
> +	TORCH_INTENSITY,
> +	INDICATOR_INTENSITY,
> +	STROBE_SOURCE,
> +	FLASH_STROBE,
> +	STROBE_STOP,
> +	STROBE_STATUS,

I think it'd be good to say e.g. in a comment here which values are still
applicable to the struct v4l2_flash field ctrls.

> +	FLASH_TIMEOUT,
> +	FLASH_INTENSITY,
> +	FLASH_FAULT,
> +	SYNC_STROBE,
> +	NUM_FLASH_CTRLS,
> +};
> +
> +/*
> + * struct v4l2_flash_ctrl_data - flash control initialization data -
> + *				 filled basing on the features declared
> + *				 by the LED Flash class driver
> + * @config:	initialization data for a control
> + * @supported:	indicates whether a control is supported
> + *		by the LED Flash class driver
> + */
> +struct v4l2_flash_ctrl_data {
> +	struct v4l2_ctrl_config config;
> +	bool supported;

Every control has an id, right? Could you use that one instead of
"supported"?

> +};
> +
> +struct v4l2_flash_ops {
> +	/* setup strobing the flash by hardware pin state assertion */
> +	int (*external_strobe_set)(struct v4l2_flash *v4l2_flash,
> +					bool enable);
> +};
> +
> +/**
> + * struct v4l2_flash_ctrl_config - V4L2 Flash controls initialization data
> + * @intensity:			constraints for the led in a non-flash mode
> + * @flash_intensity:		V4L2_CID_FLASH_INTENSITY settings constraints
> + * @flash_timeout:		V4L2_CID_FLASH_TIMEOUT constraints
> + * @flash_faults:		possible flash faults
> + * @has_external_strobe:	external strobe capability
> + * @indicator_led:		signifies that a led is of indicator type
> + */
> +struct v4l2_flash_ctrl_config {
> +	struct v4l2_ctrl_config intensity;
> +	struct v4l2_ctrl_config flash_intensity;
> +	struct v4l2_ctrl_config flash_timeout;
> +	u32 flash_faults;
> +	bool has_external_strobe:1;
> +	bool indicator_led:1;
> +};
> +
> +/**
> + * struct v4l2_flash - Flash sub-device context
> + * @fled_cdev:		LED Flash Class device controlled by this sub-device
> + * @ops:		V4L2 specific flash ops
> + * @sd:			V4L2 sub-device
> + * @hdl:		flash controls handler
> + * @ctrls:		array of pointers to controls, whose values define
> + *			the sub-device state
> + * @sync_strobe_menu	leds available for flash strobe synchronization
> + */
> +struct v4l2_flash {
> +	struct led_classdev_flash *fled_cdev;
> +	const struct v4l2_flash_ops *ops;
> +
> +	struct v4l2_subdev sd;
> +	struct v4l2_ctrl_handler hdl;
> +	struct v4l2_ctrl *ctrls[STROBE_SOURCE + 1];
> +	char **sync_strobe_menu;
> +};
> +
> +static inline struct v4l2_flash *v4l2_subdev_to_v4l2_flash(
> +							struct v4l2_subdev *sd)
> +{
> +	return container_of(sd, struct v4l2_flash, sd);
> +}
> +
> +static inline struct v4l2_flash *v4l2_ctrl_to_v4l2_flash(struct v4l2_ctrl *c)
> +{
> +	return container_of(c->handler, struct v4l2_flash, hdl);
> +}
> +
> +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
> +/**
> + * v4l2_flash_init - initialize V4L2 flash led sub-device
> + * @fled_cdev:	the LED Flash Class device to wrap
> + * @flash_ops:	V4L2 Flash device ops
> + * @config:	initialization data for V4L2 Flash controls
> + *
> + * Create V4L2 subdev 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_init(struct led_classdev_flash *fled_cdev,
> +				   const struct v4l2_flash_ops *ops,
> +				   struct v4l2_flash_ctrl_config *config);
> +
> +/**
> + * v4l2_flash_release - release V4L2 Flash sub-device
> + * @flash: the V4L2 Flash device to release
> + *
> + * Release V4L2 flash led subdev.
> + */
> +void v4l2_flash_release(struct v4l2_flash *v4l2_flash);
> +
> +#else
> +#define v4l2_flash_init(fled_cdev, ops, config) (NULL)
> +#define v4l2_flash_release(v4l2_flash)
> +#endif /* CONFIG_V4L2_FLASH_LED_CLASS */
> +
> +#endif /* _V4L2_FLASH_H */

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices
  2015-02-05 17:59   ` Sakari Ailus
@ 2015-02-09 11:15     ` Jacek Anaszewski
  0 siblings, 0 replies; 107+ messages in thread
From: Jacek Anaszewski @ 2015-02-09 11:15 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-leds, linux-media, linux-kernel, devicetree, kyungmin.park,
	b.zolnierkie, pavel, cooloney, rpurdie, s.nawrocki, Hans Verkuil

Hi Sakari,

Thanks for the review.

On 02/05/2015 06:59 PM, Sakari Ailus wrote:
> Hi Jacek,
>
> Thank you for your continuous efforts on this! I think this ended up being
> more complicated than I originally anticipated.
>
> On Fri, Jan 09, 2015 at 04:23:05PM +0100, Jacek Anaszewski wrote:
>> This patch adds helper functions for registering/unregistering
>> LED Flash class devices as V4L2 sub-devices. The functions should
>> be called from the LED subsystem device driver. In case the
>> support for V4L2 Flash sub-devices is disabled in the kernel
>> config the functions' empty versions will be used.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
>> Cc: Sakari Ailus <sakari.ailus@iki.fi>
>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
>> ---
>>   drivers/media/v4l2-core/Kconfig      |   11 +
>>   drivers/media/v4l2-core/Makefile     |    2 +
>>   drivers/media/v4l2-core/v4l2-flash.c |  581 ++++++++++++++++++++++++++++++++++
>>   include/media/v4l2-flash.h           |  139 ++++++++
>>   4 files changed, 733 insertions(+)
>>   create mode 100644 drivers/media/v4l2-core/v4l2-flash.c
>>   create mode 100644 include/media/v4l2-flash.h
>>
>> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
>> index ba7e21a..f034f1a 100644
>> --- a/drivers/media/v4l2-core/Kconfig
>> +++ b/drivers/media/v4l2-core/Kconfig
>> @@ -44,6 +44,17 @@ config V4L2_MEM2MEM_DEV
>>           tristate
>>           depends on VIDEOBUF2_CORE
>>
>> +# Used by LED subsystem flash drivers
>> +config V4L2_FLASH_LED_CLASS
>> +	tristate "Enable support for Flash sub-devices"
>> +	depends on VIDEO_V4L2_SUBDEV_API
>> +	depends on LEDS_CLASS_FLASH
>> +	---help---
>> +	  Say Y here to enable support for Flash sub-devices, which allow
>> +	  to control LED class devices with use of V4L2 Flash controls.
>> +
>> +	  When in doubt, say N.
>> +
>>   # Used by drivers that need Videobuf modules
>>   config VIDEOBUF_GEN
>>   	tristate
>> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
>> index 63d29f2..44e858c 100644
>> --- a/drivers/media/v4l2-core/Makefile
>> +++ b/drivers/media/v4l2-core/Makefile
>> @@ -22,6 +22,8 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
>>
>>   obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
>>
>> +obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash.o
>> +
>>   obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
>>   obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
>>   obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
>> diff --git a/drivers/media/v4l2-core/v4l2-flash.c b/drivers/media/v4l2-core/v4l2-flash.c
>> new file mode 100644
>> index 0000000..3fd6a08
>> --- /dev/null
>> +++ b/drivers/media/v4l2-core/v4l2-flash.c
>> @@ -0,0 +1,581 @@
>> +/*
>> + * V4L2 Flash LED sub-device registration helpers.
>> + *
>> + *	Copyright (C) 2015 Samsung Electronics Co., Ltd
>> + *	Author: Jacek Anaszewski <j.anaszewski@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation."
>> + */
>> +
>> +#include <linux/led-class-flash.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/slab.h>
>> +#include <linux/types.h>
>> +#include <media/v4l2-flash.h>
>> +
>> +#define has_flash_op(v4l2_flash, op)			\
>> +	(v4l2_flash && v4l2_flash->ops->op)
>> +
>> +#define call_flash_op(v4l2_flash, op, args...)		\
>> +		(has_flash_op(v4l2_flash, op) ?		\
>> +			v4l2_flash->ops->op(args) :	\
>
> Wouldn't you need __VA_ARGS__ here to deliver the variable argument to the
> callee? Do you need variable arguments for the current flash ops?

Indeed, it would allow to avoid the need for passing v4l2_flash
argument twice. Nonetheless, as currently we have only one op, the macro
can have fixed number of arguments.

>> +			-EINVAL)
>> +
>> +static inline enum led_brightness v4l2_flash_intensity_to_led_brightness(
>
> I'd drop inline and let the compiler decide. Same below.

Yes, this is a residue from the previous versions when the function
had single line probably.

>> +					struct v4l2_ctrl **ctrls,
>> +					enum ctrl_init_data_id cdata_id,
>> +					s32 intensity)
>> +{
>> +	struct v4l2_ctrl *ctrl = ctrls[cdata_id];
>> +	s64 __intensity = intensity - ctrl->minimum;
>> +
>> +	do_div(__intensity, ctrl->step);
>> +
>> +	/*
>> +	 * Indicator leds, unlike torch leds, are turned on/off basing on
>> +	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
>> +	 * Therefore it must be possible to set it to 0 level which in
>> +	 * the LED subsystem reflects LED_OFF state.
>> +	 */
>> +	if (cdata_id != INDICATOR_INTENSITY)
>> +		++__intensity;
>> +
>> +	return __intensity;
>> +}
>> +
>> +static inline s32 v4l2_flash_led_brightness_to_intensity(
>> +					struct v4l2_ctrl **ctrls,
>> +					enum ctrl_init_data_id cdata_id,
>
> Could you pass a pointer to struct v4l2_ctrl instead?

Good point.

>> +					enum led_brightness brightness)
>> +{
>> +	struct v4l2_ctrl *ctrl = ctrls[cdata_id];
>> +
>> +	/*
>> +	 * Indicator leds, unlike torch leds, are turned on/off basing on
>> +	 * the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only.
>> +	 * Do not decrement brightness read from the LED subsystem for
>> +	 * indicator led as it may equal 0. For torch leds this function
>> +	 * is called only when V4L2_FLASH_LED_MODE_TORCH is set and the
>> +	 * brightness read is guaranteed to be greater than 0. In the mode
>> +	 * V4L2_FLASH_LED_MODE_NONE the cached torch intensity value is used.
>> +	 */
>> +	if (cdata_id != INDICATOR_INTENSITY)
>> +		--brightness;
>> +
>> +	return (brightness * ctrl->step) + ctrl->minimum;
>> +}
>> +
>> +static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c)
>> +{
>> +	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 v4l2_ctrl **ctrls = v4l2_flash->ctrls;
>> +	bool is_strobing;
>> +	int ret;
>> +
>> +	switch (c->id) {
>> +	case V4L2_CID_FLASH_TORCH_INTENSITY:
>> +		/*
>> +		 * Update torch brightness only if in TORCH_MODE.
>> +		 * In other modes torch led is turned off, which
>> +		 * would spuriously inform the user space that
>> +		 * V4L2_CID_FLASH_TORCH_INTENSITY control setting
>> +		 * has changed.
>> +		 */
>> +		if (ctrls[LED_MODE]->val == V4L2_FLASH_LED_MODE_TORCH) {
>> +			ret = led_update_brightness(led_cdev);
>> +			if (ret < 0)
>> +				return ret;
>> +			c->val = v4l2_flash_led_brightness_to_intensity(
>> +							ctrls, TORCH_INTENSITY,
>> +							led_cdev->brightness);
>> +		}
>> +		return 0;
>> +	case V4L2_CID_FLASH_INDICATOR_INTENSITY:
>> +		ret = led_update_brightness(led_cdev);
>> +		if (ret < 0)
>> +			return ret;
>> +		c->val = v4l2_flash_led_brightness_to_intensity(
>> +						ctrls, INDICATOR_INTENSITY,
>> +						led_cdev->brightness);
>> +		return 0;
>> +	case V4L2_CID_FLASH_INTENSITY:
>> +		ret = led_update_flash_brightness(fled_cdev);
>> +		if (ret < 0)
>> +			return ret;
>> +		/* no conversion is needed */
>> +		c->val = fled_cdev->brightness.val;
>> +		return 0;
>> +	case V4L2_CID_FLASH_STROBE_STATUS:
>> +		ret = led_get_flash_strobe(fled_cdev, &is_strobing);
>> +		if (ret < 0)
>> +			return ret;
>> +		c->val = is_strobing;
>> +		return 0;
>> +	case V4L2_CID_FLASH_FAULT:
>> +		/* led faults map directly to V4L2 flash faults */
>> +		return led_get_flash_fault(fled_cdev, &c->val);
>> +	case V4L2_CID_FLASH_SYNC_STROBE:
>> +		c->val = fled_cdev->sync_led_id;
>> +		return 0;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
>> +{
>> +	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 v4l2_ctrl **ctrls = v4l2_flash->ctrls;
>> +	enum led_brightness brightness;
>> +	bool external_strobe;
>> +	int ret = 0;
>> +
>> +	switch (c->id) {
>> +	case V4L2_CID_FLASH_LED_MODE:
>> +		switch (c->val) {
>> +		case V4L2_FLASH_LED_MODE_NONE:
>> +			led_set_brightness(led_cdev, LED_OFF);
>> +			return led_set_flash_strobe(fled_cdev, false);
>> +		case V4L2_FLASH_LED_MODE_FLASH:
>> +			/* Turn the torch LED off */
>> +			led_set_brightness(led_cdev, LED_OFF);
>> +			external_strobe = (ctrls[STROBE_SOURCE]->val ==
>> +					V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
>> +
>> +			if (has_flash_op(v4l2_flash, external_strobe_set))
>> +				ret = call_flash_op(v4l2_flash,
>> +						external_strobe_set, v4l2_flash,
>> +						external_strobe);
>> +			return ret;
>> +		case V4L2_FLASH_LED_MODE_TORCH:
>> +			/* Stop flash strobing */
>> +			ret = led_set_flash_strobe(fled_cdev, false);
>> +			if (ret < 0)
>> +				return ret;
>> +
>> +			brightness =
>> +				v4l2_flash_intensity_to_led_brightness(
>> +						ctrls, TORCH_INTENSITY,
>> +						ctrls[TORCH_INTENSITY]->val);
>> +			led_set_brightness(led_cdev, brightness);
>> +			return 0;
>> +		}
>> +		break;
>> +	case V4L2_CID_FLASH_STROBE_SOURCE:
>> +		external_strobe = (c->val == V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
>> +
>> +		return call_flash_op(v4l2_flash, external_strobe_set,
>> +					v4l2_flash, external_strobe);
>> +	case V4L2_CID_FLASH_STROBE:
>> +		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH ||
>> +		    ctrls[STROBE_SOURCE]->val !=
>> +					V4L2_FLASH_STROBE_SOURCE_SOFTWARE)
>> +			return -EINVAL;
>> +		return led_set_flash_strobe(fled_cdev, true);
>> +	case V4L2_CID_FLASH_STROBE_STOP:
>> +		if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_FLASH ||
>> +		    ctrls[STROBE_SOURCE]->val !=
>> +					V4L2_FLASH_STROBE_SOURCE_SOFTWARE)
>> +			return -EINVAL;
>> +		return led_set_flash_strobe(fled_cdev, false);
>> +	case V4L2_CID_FLASH_TIMEOUT:
>> +		/* no conversion is needed */
>> +		return led_set_flash_timeout(fled_cdev, c->val);
>> +	case V4L2_CID_FLASH_INTENSITY:
>> +		/* no conversion is needed */
>> +		return led_set_flash_brightness(fled_cdev, c->val);
>> +	case V4L2_CID_FLASH_INDICATOR_INTENSITY:
>> +		brightness = v4l2_flash_intensity_to_led_brightness(
>> +						ctrls, INDICATOR_INTENSITY,
>> +						c->val);
>> +		led_set_brightness(led_cdev, brightness);
>> +		return 0;
>> +	case V4L2_CID_FLASH_TORCH_INTENSITY:
>> +		/*
>> +		 * If not in MODE_TORCH don't call led-class brightness_set
>> +		 * op, as it would result in turning the torch led on.
>> +		 * Instead the value is cached only and will be written
>> +		 * to the device upon transition to MODE_TORCH.
>> +		 */
>> +		if (ctrls[LED_MODE]->val == V4L2_FLASH_LED_MODE_TORCH) {
>> +			brightness =
>> +				v4l2_flash_intensity_to_led_brightness(
>> +							ctrls, TORCH_INTENSITY,
>> +							c->val);
>> +			led_set_brightness(led_cdev, brightness);
>> +		}
>> +		return 0;
>> +	case V4L2_CID_FLASH_SYNC_STROBE:
>> +		fled_cdev->sync_led_id = c->val;
>> +		return 0;
>> +	}
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops = {
>> +	.g_volatile_ctrl = v4l2_flash_g_volatile_ctrl,
>> +	.s_ctrl = v4l2_flash_s_ctrl,
>> +};
>> +
>> +static void fill_ctrl_init_data(struct v4l2_flash *v4l2_flash,
>> +			  struct v4l2_flash_ctrl_config *flash_ctrl_cfg,
>> +			  struct v4l2_flash_ctrl_data *ctrl_init_data)
>> +{
>> +	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
>> +	const struct led_flash_ops *fled_cdev_ops = fled_cdev->ops;
>> +	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
>> +	struct v4l2_ctrl_config *ctrl_cfg;
>> +	u32 mask;
>> +	s64 max;
>> +
>> +	/* Init FLASH_FAULT ctrl data */
>> +	if (flash_ctrl_cfg->flash_faults) {
>> +		ctrl_init_data[FLASH_FAULT].supported = true;
>> +		ctrl_cfg = &ctrl_init_data[FLASH_FAULT].config;
>> +		ctrl_cfg->id = V4L2_CID_FLASH_FAULT;
>> +		ctrl_cfg->max = flash_ctrl_cfg->flash_faults;
>> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
>> +				  V4L2_CTRL_FLAG_READ_ONLY;
>> +	}
>> +
>> +	/* Init INDICATOR_INTENSITY ctrl data */
>> +	if (flash_ctrl_cfg->indicator_led) {
>> +		ctrl_init_data[INDICATOR_INTENSITY].supported = true;
>> +		ctrl_init_data[INDICATOR_INTENSITY].config =
>> +						flash_ctrl_cfg->intensity;
>> +		ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config;
>> +		ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY;
>> +		ctrl_cfg->min = 0;
>> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
>> +
>> +		/* Indicator LED can have only faults and intensity controls. */
>> +		return;
>> +	}
>> +
>> +	/* Init FLASH_LED_MODE ctrl data */
>> +	mask = 1 << V4L2_FLASH_LED_MODE_NONE |
>> +	       1 << V4L2_FLASH_LED_MODE_TORCH;
>> +	if (led_cdev->flags & LED_DEV_CAP_FLASH)
>> +		mask |= 1 << V4L2_FLASH_LED_MODE_FLASH;
>> +
>> +	ctrl_init_data[LED_MODE].supported = true;
>> +	ctrl_cfg = &ctrl_init_data[LED_MODE].config;
>> +	ctrl_cfg->id = V4L2_CID_FLASH_LED_MODE;
>> +	ctrl_cfg->max = V4L2_FLASH_LED_MODE_TORCH;
>> +	ctrl_cfg->menu_skip_mask = ~mask;
>> +	ctrl_cfg->def = V4L2_FLASH_LED_MODE_NONE;
>> +	ctrl_cfg->flags = 0;
>> +
>> +	/* Init TORCH_INTENSITY ctrl data */
>> +	ctrl_init_data[TORCH_INTENSITY].supported = true;
>> +	ctrl_init_data[TORCH_INTENSITY].config = flash_ctrl_cfg->intensity;
>> +	ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config;
>> +	ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY;
>> +	ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
>> +
>> +	if (!(led_cdev->flags & LED_DEV_CAP_FLASH))
>> +		return;
>> +
>> +	/* Init FLASH_STROBE_SOURCE ctrl data */
>> +	mask = 1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
>> +	if (flash_ctrl_cfg->has_external_strobe) {
>> +		mask |= 1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
>> +		max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
>> +	} else {
>> +		max = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
>> +	}
>> +
>> +	ctrl_init_data[STROBE_SOURCE].supported = true;
>> +	ctrl_cfg = &ctrl_init_data[STROBE_SOURCE].config;
>> +	ctrl_cfg->id = V4L2_CID_FLASH_STROBE_SOURCE;
>> +	ctrl_cfg->max = max;
>> +	ctrl_cfg->menu_skip_mask = ~mask;
>> +	ctrl_cfg->def = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
>> +
>> +	/* Init FLASH_STROBE ctrl data */
>> +	ctrl_init_data[FLASH_STROBE].supported = true;
>> +	ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config;
>> +	ctrl_cfg->id = V4L2_CID_FLASH_STROBE;
>> +
>> +	/* Init STROBE_STOP ctrl data */
>> +	ctrl_init_data[STROBE_STOP].supported = true;
>> +	ctrl_cfg = &ctrl_init_data[STROBE_STOP].config;
>> +	ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STOP;
>> +
>> +	/* Init STROBE_STATUS ctrl data */
>> +	if (fled_cdev_ops->strobe_get) {
>> +		ctrl_init_data[STROBE_STATUS].supported = true;
>> +		ctrl_cfg = &ctrl_init_data[STROBE_STATUS].config;
>> +		ctrl_cfg->id = V4L2_CID_FLASH_STROBE_STATUS;
>> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE |
>> +				  V4L2_CTRL_FLAG_READ_ONLY;
>> +	}
>> +
>> +	/* Init FLASH_TIMEOUT ctrl data */
>> +	if (fled_cdev_ops->timeout_set) {
>> +		ctrl_init_data[FLASH_TIMEOUT].supported = true;
>> +		ctrl_init_data[FLASH_TIMEOUT].config =
>> +					flash_ctrl_cfg->flash_timeout;
>> +		ctrl_cfg = &ctrl_init_data[FLASH_TIMEOUT].config;
>> +		ctrl_cfg->id = V4L2_CID_FLASH_TIMEOUT;
>> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
>> +	}
>> +
>> +	/* Init FLASH_INTENSITY ctrl data */
>> +	if (fled_cdev_ops->flash_brightness_set) {
>> +		ctrl_init_data[FLASH_INTENSITY].supported = true;
>> +		ctrl_init_data[FLASH_INTENSITY].config =
>> +					flash_ctrl_cfg->flash_intensity;
>> +		ctrl_cfg = &ctrl_init_data[FLASH_INTENSITY].config;
>> +		ctrl_cfg->id = V4L2_CID_FLASH_INTENSITY;
>> +		ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE;
>> +	}
>> +}
>> +
>> +static int v4l2_flash_init_sync_strobe_menu(struct v4l2_flash *v4l2_flash)
>> +{
>> +	struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev;
>> +	struct v4l2_ctrl *ctrl;
>> +	int i = 0;
>> +
>> +	v4l2_flash->sync_strobe_menu =
>> +			devm_kcalloc(fled_cdev->led_cdev.dev->parent,
>> +					fled_cdev->num_sync_leds + 1,
>> +					sizeof(*fled_cdev),
>> +					GFP_KERNEL);
>> +
>> +	if (!v4l2_flash->sync_strobe_menu)
>> +		return -ENOMEM;
>> +
>> +	v4l2_flash->sync_strobe_menu[0] = "none";
>> +
>> +	for (i = 0; i < fled_cdev->num_sync_leds; ++i)
>> +		v4l2_flash->sync_strobe_menu[i + 1] =
>> +				(char *) fled_cdev->sync_leds[i]->led_cdev.name;
>
> What's here, and where does it come from?
>
> The rest of the sub-devices typically have a device's (chip's) name and the
> bus address (usually i2c).

It comes from the struct led_classdev's 'name' property, which is
assigned a pointer to the parsed 'label' DT property (LEDs common 
bindings) string. It has to be unique as it is passed to the
device_create_with_groups in the led-class.c

We can't use device's name and I2C bus address, as a v4l2-flash sub-dev
is created per discrete LED element, not per device (many v4l2-flash
sub-devs can be created per one flash LED device).

>> +	ctrl = v4l2_ctrl_new_std_menu_items(
>> +		&v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
>> +		V4L2_CID_FLASH_SYNC_STROBE,
>> +		fled_cdev->num_sync_leds,
>> +		0, 0,
>> +		(const char * const *) v4l2_flash->sync_strobe_menu);
>
> Do you need the casting here?

Yes, there is warning generated without it:

drivers/media/v4l2-core/v4l2-flash.c:364:3: warning: passing argument 7 
of ‘v4l2_ctrl_new_std_menu_items’ from incompatible pointer type 
[enabled by default]
include/media/v4l2-ctrls.h:408:19: note: expected ‘const char * const*’ 
but argument is of type ‘char **’

>> +
>> +	if (ctrl)
>> +		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
>> +
>> +	return 0;
>> +}
>> +
>> +static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash,
>> +				struct v4l2_flash_ctrl_config *flash_ctrl_cfg)
>> +
>> +{
>> +	struct led_classdev *led_cdev = &v4l2_flash->fled_cdev->led_cdev;
>> +	struct v4l2_flash_ctrl_data *ctrl_init_data;
>> +	struct v4l2_ctrl *ctrl;
>> +	struct v4l2_ctrl_config *ctrl_cfg;
>> +	int i, ret, num_ctrls = 0;
>> +
>> +	/* allocate memory dynamically so as not to exceed stack frame size */
>> +	ctrl_init_data = kcalloc(NUM_FLASH_CTRLS, sizeof(*ctrl_init_data),
>> +					GFP_KERNEL);
>> +	if (!ctrl_init_data)
>> +		return -ENOMEM;
>> +
>> +	memset(ctrl_init_data, 0, sizeof(*ctrl_init_data));
>
> kcalloc() clears the memory, no need to do it again.

Right.

>> +	fill_ctrl_init_data(v4l2_flash, flash_ctrl_cfg, ctrl_init_data);
>> +
>> +	for (i = 0; i < NUM_FLASH_CTRLS; ++i)
>> +		if (ctrl_init_data[i].supported)
>> +			++num_ctrls;
>> +
>> +	v4l2_ctrl_handler_init(&v4l2_flash->hdl, num_ctrls);
>> +
>> +	for (i = 0; i < NUM_FLASH_CTRLS; ++i) {
>> +		ctrl_cfg = &ctrl_init_data[i].config;
>> +		if (!ctrl_init_data[i].supported)
>> +			continue;
>> +
>> +		if (ctrl_cfg->id == V4L2_CID_FLASH_LED_MODE ||
>> +		    ctrl_cfg->id == V4L2_CID_FLASH_STROBE_SOURCE)
>> +			ctrl = v4l2_ctrl_new_std_menu(&v4l2_flash->hdl,
>> +						&v4l2_flash_ctrl_ops,
>> +						ctrl_cfg->id,
>> +						ctrl_cfg->max,
>> +						ctrl_cfg->menu_skip_mask,
>> +						ctrl_cfg->def);
>> +		else
>> +			ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl,
>> +						&v4l2_flash_ctrl_ops,
>> +						ctrl_cfg->id,
>> +						ctrl_cfg->min,
>> +						ctrl_cfg->max,
>> +						ctrl_cfg->step,
>> +						ctrl_cfg->def);
>> +
>> +		if (ctrl)
>> +			ctrl->flags |= ctrl_cfg->flags;
>> +
>> +		if (i <= STROBE_SOURCE)
>> +			v4l2_flash->ctrls[i] = ctrl;
>> +	}
>> +
>> +	kfree(ctrl_init_data);
>> +
>> +	if (led_cdev->flags & LED_DEV_CAP_SYNC_STROBE) {
>> +		ret = v4l2_flash_init_sync_strobe_menu(v4l2_flash);
>> +		if (ret < 0)
>> +			goto error_free_handler;
>> +	}
>> +
>> +	if (v4l2_flash->hdl.error) {
>> +		ret = v4l2_flash->hdl.error;
>> +		goto error_free_handler;
>> +	}
>> +
>> +	v4l2_ctrl_handler_setup(&v4l2_flash->hdl);
>> +
>> +	v4l2_flash->sd.ctrl_handler = &v4l2_flash->hdl;
>> +
>> +	return 0;
>> +
>> +error_free_handler:
>> +	v4l2_ctrl_handler_free(&v4l2_flash->hdl);
>> +	return ret;
>> +}
>> +
>> +/*
>> + * V4L2 subdev internal operations
>> + */
>> +
>> +static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>> +{
>> +	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;
>> +	int ret = 0;
>> +
>> +	mutex_lock(&led_cdev->led_access);
>> +
>> +	if (!v4l2_fh_is_singular(&fh->vfh)) {
>> +		ret = -EBUSY;
>> +		goto unlock;
>> +	}
>> +
>> +	led_sysfs_disable(led_cdev);
>> +
>> +unlock:
>> +	mutex_unlock(&led_cdev->led_access);
>> +	return ret;
>> +}
>> +
>> +static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>> +{
>> +	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;
>> +	int ret = 0;
>> +
>> +	mutex_lock(&led_cdev->led_access);
>> +
>> +	if (has_flash_op(v4l2_flash, external_strobe_set))
>> +		ret = call_flash_op(v4l2_flash, external_strobe_set,
>> +				v4l2_flash, false);
>> +	led_sysfs_enable(led_cdev);
>> +
>> +	mutex_unlock(&led_cdev->led_access);
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = {
>> +	.open = v4l2_flash_open,
>> +	.close = v4l2_flash_close,
>> +};
>> +
>> +static const struct v4l2_subdev_core_ops v4l2_flash_core_ops = {
>> +	.queryctrl = v4l2_subdev_queryctrl,
>> +	.querymenu = v4l2_subdev_querymenu,
>> +};
>> +
>> +static const struct v4l2_subdev_ops v4l2_flash_subdev_ops = {
>> +	.core = &v4l2_flash_core_ops,
>> +};
>> +
>> +struct v4l2_flash *v4l2_flash_init(struct led_classdev_flash *fled_cdev,
>> +				   const struct v4l2_flash_ops *ops,
>> +				   struct v4l2_flash_ctrl_config *config)
>> +{
>> +	struct v4l2_flash *v4l2_flash;
>> +	struct led_classdev *led_cdev = &fled_cdev->led_cdev;
>> +	struct v4l2_subdev *sd;
>> +	int ret;
>> +
>> +	if (!fled_cdev || !ops || !config)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	v4l2_flash = kzalloc(sizeof(*v4l2_flash), GFP_KERNEL);
>> +	if (!v4l2_flash)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	sd = &v4l2_flash->sd;
>> +	v4l2_flash->fled_cdev = fled_cdev;
>> +	v4l2_flash->ops = ops;
>> +	sd->dev = led_cdev->dev;
>> +	v4l2_subdev_init(sd, &v4l2_flash_subdev_ops);
>> +	sd->internal_ops = &v4l2_flash_subdev_internal_ops;
>> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
>> +	snprintf(sd->name, sizeof(sd->name), led_cdev->name);
>
> strlcpy() or snprintf(sd->name, sizeof(), "%s", led_cdev->name).

I think that strlcpy will fit here best.

>> +
>> +	ret = v4l2_flash_init_controls(v4l2_flash, config);
>> +	if (ret < 0)
>> +		goto err_init_controls;
>> +
>> +	ret = media_entity_init(&sd->entity, 0, NULL, 0);
>> +	if (ret < 0)
>> +		goto err_init_entity;
>> +
>> +	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
>> +
>> +	ret = v4l2_async_register_subdev(sd);
>> +	if (ret < 0)
>> +		goto err_init_entity;
>> +
>> +	return v4l2_flash;
>> +
>> +err_init_entity:
>> +	media_entity_cleanup(&sd->entity);
>
> media_entity_cleanup() can be called on an uninitialised entity (as long as
> it's zeroed). So you could simplity this a little. Up to you.
>
>> +err_init_controls:
>> +	v4l2_ctrl_handler_free(sd->ctrl_handler);
>> +	kfree(v4l2_flash);
>> +
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(v4l2_flash_init);
>> +
>> +void v4l2_flash_release(struct v4l2_flash *v4l2_flash)
>> +{
>> +	struct v4l2_subdev *sd = &v4l2_flash->sd;
>> +
>> +	if (!v4l2_flash)
>> +		return;
>> +
>> +	v4l2_async_unregister_subdev(sd);
>> +	media_entity_cleanup(&sd->entity);
>> +	v4l2_ctrl_handler_free(sd->ctrl_handler);
>> +	kfree(v4l2_flash);
>> +}
>> +EXPORT_SYMBOL_GPL(v4l2_flash_release);
>> +
>> +MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
>> +MODULE_DESCRIPTION("V4L2 Flash sub-device helpers");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/media/v4l2-flash.h b/include/media/v4l2-flash.h
>> new file mode 100644
>> index 0000000..404b5a8
>> --- /dev/null
>> +++ b/include/media/v4l2-flash.h
>> @@ -0,0 +1,139 @@
>> +/*
>> + * V4L2 Flash LED sub-device registration helpers.
>> + *
>> + *	Copyright (C) 2015 Samsung Electronics Co., Ltd
>> + *	Author: Jacek Anaszewski <j.anaszewski@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation."
>
> There's an unbalanced quote here. Is that intended? Same in the .c file.

This is unintended, to be removed.

>> + */
>> +
>> +#ifndef _V4L2_FLASH_H
>> +#define _V4L2_FLASH_H
>> +
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-device.h>
>> +#include <media/v4l2-dev.h>
>> +#include <media/v4l2-event.h>
>> +#include <media/v4l2-ioctl.h>
>
> Do you need all the above headers here?

Actually no - only media/v4l2-ctrls.h nad media/v4l2-subdev.h are
required. I will fix this.

>> +
>> +struct led_classdev_flash;
>> +struct led_classdev;
>> +struct v4l2_flash;
>> +enum led_brightness;
>> +
>> +enum ctrl_init_data_id {
>> +	LED_MODE,
>> +	TORCH_INTENSITY,
>> +	INDICATOR_INTENSITY,
>> +	STROBE_SOURCE,
>> +	FLASH_STROBE,
>> +	STROBE_STOP,
>> +	STROBE_STATUS,
>
> I think it'd be good to say e.g. in a comment here which values are still
> applicable to the struct v4l2_flash field ctrls.

OK.

>> +	FLASH_TIMEOUT,
>> +	FLASH_INTENSITY,
>> +	FLASH_FAULT,
>> +	SYNC_STROBE,
>> +	NUM_FLASH_CTRLS,
>> +};
>> +
>> +/*
>> + * struct v4l2_flash_ctrl_data - flash control initialization data -
>> + *				 filled basing on the features declared
>> + *				 by the LED Flash class driver
>> + * @config:	initialization data for a control
>> + * @supported:	indicates whether a control is supported
>> + *		by the LED Flash class driver
>> + */
>> +struct v4l2_flash_ctrl_data {
>> +	struct v4l2_ctrl_config config;
>> +	bool supported;
>
> Every control has an id, right? Could you use that one instead of
> "supported"?

OK.

>> +};
>> +
>> +struct v4l2_flash_ops {
>> +	/* setup strobing the flash by hardware pin state assertion */
>> +	int (*external_strobe_set)(struct v4l2_flash *v4l2_flash,
>> +					bool enable);
>> +};
>> +
>> +/**
>> + * struct v4l2_flash_ctrl_config - V4L2 Flash controls initialization data
>> + * @intensity:			constraints for the led in a non-flash mode
>> + * @flash_intensity:		V4L2_CID_FLASH_INTENSITY settings constraints
>> + * @flash_timeout:		V4L2_CID_FLASH_TIMEOUT constraints
>> + * @flash_faults:		possible flash faults
>> + * @has_external_strobe:	external strobe capability
>> + * @indicator_led:		signifies that a led is of indicator type
>> + */
>> +struct v4l2_flash_ctrl_config {
>> +	struct v4l2_ctrl_config intensity;
>> +	struct v4l2_ctrl_config flash_intensity;
>> +	struct v4l2_ctrl_config flash_timeout;
>> +	u32 flash_faults;
>> +	bool has_external_strobe:1;
>> +	bool indicator_led:1;
>> +};
>> +
>> +/**
>> + * struct v4l2_flash - Flash sub-device context
>> + * @fled_cdev:		LED Flash Class device controlled by this sub-device
>> + * @ops:		V4L2 specific flash ops
>> + * @sd:			V4L2 sub-device
>> + * @hdl:		flash controls handler
>> + * @ctrls:		array of pointers to controls, whose values define
>> + *			the sub-device state
>> + * @sync_strobe_menu	leds available for flash strobe synchronization
>> + */
>> +struct v4l2_flash {
>> +	struct led_classdev_flash *fled_cdev;
>> +	const struct v4l2_flash_ops *ops;
>> +
>> +	struct v4l2_subdev sd;
>> +	struct v4l2_ctrl_handler hdl;
>> +	struct v4l2_ctrl *ctrls[STROBE_SOURCE + 1];
>> +	char **sync_strobe_menu;
>> +};
>> +
>> +static inline struct v4l2_flash *v4l2_subdev_to_v4l2_flash(
>> +							struct v4l2_subdev *sd)
>> +{
>> +	return container_of(sd, struct v4l2_flash, sd);
>> +}
>> +
>> +static inline struct v4l2_flash *v4l2_ctrl_to_v4l2_flash(struct v4l2_ctrl *c)
>> +{
>> +	return container_of(c->handler, struct v4l2_flash, hdl);
>> +}
>> +
>> +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
>> +/**
>> + * v4l2_flash_init - initialize V4L2 flash led sub-device
>> + * @fled_cdev:	the LED Flash Class device to wrap
>> + * @flash_ops:	V4L2 Flash device ops
>> + * @config:	initialization data for V4L2 Flash controls
>> + *
>> + * Create V4L2 subdev 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_init(struct led_classdev_flash *fled_cdev,
>> +				   const struct v4l2_flash_ops *ops,
>> +				   struct v4l2_flash_ctrl_config *config);
>> +
>> +/**
>> + * v4l2_flash_release - release V4L2 Flash sub-device
>> + * @flash: the V4L2 Flash device to release
>> + *
>> + * Release V4L2 flash led subdev.
>> + */
>> +void v4l2_flash_release(struct v4l2_flash *v4l2_flash);
>> +
>> +#else
>> +#define v4l2_flash_init(fled_cdev, ops, config) (NULL)
>> +#define v4l2_flash_release(v4l2_flash)
>> +#endif /* CONFIG_V4L2_FLASH_LED_CLASS */
>> +
>> +#endif /* _V4L2_FLASH_H */
>


-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply	[flat|nested] 107+ messages in thread

end of thread, other threads:[~2015-02-09 11:15 UTC | newest]

Thread overview: 107+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-09 15:22 [PATCH/RFC v10 00/19] LED / flash API integration Jacek Anaszewski
2015-01-09 15:22 ` [PATCH/RFC v10 01/19] leds: Add LED Flash class extension to the LED subsystem Jacek Anaszewski
2015-01-09 17:37   ` Pavel Machek
2015-01-26 23:02     ` Bryan Wu
2015-01-09 15:22 ` [PATCH/RFC v10 02/19] Documentation: leds: Add description of LED Flash class extension Jacek Anaszewski
2015-01-09 17:40   ` Pavel Machek
2015-01-12  8:04     ` Jacek Anaszewski
2015-01-26 23:03       ` Bryan Wu
2015-01-09 15:22 ` [PATCH/RFC v10 03/19] DT: leds: Add led-sources property Jacek Anaszewski
2015-01-09 17:42   ` Pavel Machek
     [not found]   ` <1420816989-1808-4-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-09 18:33     ` Rob Herring
2015-01-09 18:33       ` Rob Herring
2015-01-12  8:32       ` Jacek Anaszewski
2015-01-12 13:52         ` Rob Herring
2015-01-12 16:10           ` Jacek Anaszewski
2015-01-12 16:55             ` Rob Herring
2015-01-12 17:06               ` Mark Brown
2015-01-15 12:33                 ` Sylwester Nawrocki
2015-01-15 14:37                   ` Rob Herring
2015-01-15 21:03                   ` Pavel Machek
2015-01-16 10:17                     ` Sylwester Nawrocki
2015-01-16 10:17                       ` Sylwester Nawrocki
     [not found]               ` <CAL_JsqKpJtUG0G6g1GOuSVpc31oe-dp3qdrKJUE0upG-xRDFhA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-01-13  8:42                 ` Jacek Anaszewski
2015-01-13  8:42                   ` Jacek Anaszewski
2015-01-15 14:24                   ` Rob Herring
2015-01-15 15:53                     ` Mark Brown
2015-01-16  9:07                     ` Jacek Anaszewski
2015-01-16 13:48                       ` Rob Herring
     [not found]                         ` <CAL_Jsq+EFWzs1HP1tVt6P=p=HZn2AtSPjp55YrmMQi_mE+kNfQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-01-16 15:52                           ` Jacek Anaszewski
2015-01-16 15:52                             ` Jacek Anaszewski
2015-01-20 16:09                             ` Jacek Anaszewski
2015-01-20 17:29                               ` Rob Herring
2015-01-20 17:40                                 ` Pavel Machek
2015-01-21  9:39                                   ` Jacek Anaszewski
2015-01-28  7:04                                     ` Sakari Ailus
2015-01-09 15:22 ` [PATCH/RFC v10 04/19] dt-binding: mfd: max77693: Add DT binding related macros Jacek Anaszewski
2015-01-09 17:43   ` Pavel Machek
2015-01-20 11:12   ` Lee Jones
2015-01-20 12:53     ` Jacek Anaszewski
2015-01-28  8:52       ` Sakari Ailus
2015-01-09 15:22 ` [PATCH/RFC v10 05/19] mfd: max77693: Modify flash cell name identifiers Jacek Anaszewski
2015-01-09 17:53   ` Pavel Machek
     [not found]   ` <1420816989-1808-6-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-20 11:13     ` Lee Jones
2015-01-20 11:13       ` Lee Jones
2015-01-20 12:57       ` Jacek Anaszewski
2015-01-20 12:57         ` Jacek Anaszewski
2015-01-20 15:41         ` Lee Jones
2015-01-09 15:22 ` [PATCH/RFC v10 06/19] mfd: max77693: modifications around max77693_led_platform_data Jacek Anaszewski
2015-01-09 17:56   ` Pavel Machek
     [not found]   ` <1420816989-1808-7-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-20 11:15     ` Lee Jones
2015-01-20 11:15       ` Lee Jones
2015-01-09 15:22 ` [PATCH/RFC v10 07/19] mfd: max77693: Adjust FLASH_EN_SHIFT and TORCH_EN_SHIFT macros Jacek Anaszewski
2015-01-09 17:59   ` Pavel Machek
2015-01-20 11:17   ` Lee Jones
2015-01-20 13:01     ` Jacek Anaszewski
2015-01-20 14:11       ` Jacek Anaszewski
2015-01-20 15:40         ` Lee Jones
2015-01-20 16:00           ` Pavel Machek
2015-01-20 16:41             ` Lee Jones
2015-01-09 15:22 ` [PATCH/RFC v10 08/19] leds: Add support for max77693 mfd flash cell Jacek Anaszewski
     [not found]   ` <1420816989-1808-9-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-09 18:46     ` Pavel Machek
2015-01-09 18:46       ` Pavel Machek
2015-01-12  8:52       ` Jacek Anaszewski
2015-01-12 13:25         ` Pavel Machek
2015-01-12 13:46           ` Jacek Anaszewski
2015-02-05 15:34     ` Sakari Ailus
2015-02-05 15:34       ` Sakari Ailus
2015-02-05 16:26       ` Jacek Anaszewski
2015-01-09 15:22 ` [PATCH/RFC v10 09/19] DT: Add documentation for the mfd Maxim max77693 Jacek Anaszewski
2015-01-09 17:52   ` Pavel Machek
2015-01-20 11:21   ` Lee Jones
2015-01-20 14:36     ` Jacek Anaszewski
     [not found]       ` <54BE67EA.2070507-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-20 15:38         ` Lee Jones
2015-01-20 15:38           ` Lee Jones
     [not found] ` <1420816989-1808-1-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-09 15:23   ` [PATCH/RFC v10 10/19] leds: Add driver for AAT1290 current regulator Jacek Anaszewski
2015-01-09 15:23     ` Jacek Anaszewski
     [not found]     ` <1420816989-1808-11-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-09 18:57       ` Pavel Machek
2015-01-09 18:57         ` Pavel Machek
2015-01-09 15:23 ` [PATCH/RFC v10 11/19] of: Add Skyworks Solutions, Inc. vendor prefix Jacek Anaszewski
     [not found]   ` <1420816989-1808-12-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-09 18:57     ` Pavel Machek
2015-01-09 18:57       ` Pavel Machek
2015-01-09 15:23 ` [PATCH/RFC v10 12/19] DT: Add documentation for the Skyworks AAT1290 Jacek Anaszewski
2015-01-09 18:58   ` Pavel Machek
2015-01-09 15:23 ` [PATCH/RFC v10 13/19] exynos4-is: Add support for v4l2-flash subdevs Jacek Anaszewski
2015-01-09 19:06   ` Pavel Machek
2015-01-09 15:23 ` [PATCH/RFC v10 14/19] v4l2-ctrls: Add V4L2_CID_FLASH_SYNC_STROBE control Jacek Anaszewski
     [not found]   ` <1420816989-1808-15-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-09 19:06     ` Pavel Machek
2015-01-09 19:06       ` Pavel Machek
2015-02-05 16:36   ` Sakari Ailus
2015-01-09 15:23 ` [PATCH/RFC v10 15/19] media: Add registration helpers for V4L2 flash sub-devices Jacek Anaszewski
2015-01-09 20:54   ` Pavel Machek
2015-01-12  9:46     ` Jacek Anaszewski
2015-01-12  9:46       ` Jacek Anaszewski
2015-01-12 13:27       ` Pavel Machek
2015-02-05 17:59   ` Sakari Ailus
2015-02-09 11:15     ` Jacek Anaszewski
2015-01-09 15:23 ` [PATCH/RFC v10 16/19] Documentation: leds: Add description of v4l2-flash sub-device Jacek Anaszewski
2015-01-09 20:57   ` Pavel Machek
2015-01-09 15:23 ` [PATCH/RFC v10 17/19] DT: Add documentation for exynos4-is 'flashes' property Jacek Anaszewski
2015-01-09 20:57   ` Pavel Machek
2015-01-21 16:32   ` Sylwester Nawrocki
2015-01-22  8:47     ` Jacek Anaszewski
2015-01-09 15:23 ` [PATCH/RFC v10 18/19] leds: max77693: add support for V4L2 Flash sub-device Jacek Anaszewski
2015-01-09 20:59   ` Pavel Machek
2015-01-09 15:23 ` [PATCH/RFC v10 19/19] leds: aat1290: " Jacek Anaszewski
     [not found]   ` <1420816989-1808-20-git-send-email-j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-01-09 20:59     ` Pavel Machek
2015-01-09 20:59       ` Pavel Machek

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.