Hi Jacek,

On Thu, Apr 17, 2014 at 10:26:44AM +0200, Jacek Anaszewski wrote:
> Hi Sakari,
> 
> Thanks for the review.
> 
> On 04/16/2014 08:21 PM, Sakari Ailus wrote:
> >Hi Jacek,
> >
> >Thanks for the update!
> >
> [...]
> >>+static inline enum led_brightness v4l2_flash_intensity_to_led_brightness(
> >>+                                   struct led_ctrl *config,
> >>+                                   u32 intensity)
> >
> >Fits on a single line.
> >
> >>+{
> >>+   return intensity / config->step;
> >
> >Shouldn't you first decrement the minimum before the division?
> 
> Brightness level 0 means that led is off. Let's consider following case:
> 
> intensity - 15625
> config->step - 15625
> intensity / config->step = 1 (the lowest possible current level)

In V4L2 controls the minimum is not off, and zero might not be a possible
value since minimum isn't divisible by step.

I wonder how to best take that into account.

> >>+}
> >>+
> >>+static inline u32 v4l2_flash_led_brightness_to_intensity(
> >>+                                   struct led_ctrl *config,
> >>+                                   enum led_brightness brightness)
> >>+{
> >>+   return brightness * config->step;
> >
> >And do the opposite here?

..

> >>+                   return -EINVAL;
> >>+           return v4l2_call_flash_op(strobe_set, led_cdev, true);
> >>+   case V4L2_CID_FLASH_STROBE_STOP:
> >>+           return v4l2_call_flash_op(strobe_set, led_cdev, false);
> >>+   case V4L2_CID_FLASH_TIMEOUT:
> >>+           ret =  v4l2_call_flash_op(timeout_set, led_cdev, c->val);
> >>+   case V4L2_CID_FLASH_INTENSITY:
> >>+           /* no conversion is needed */
> >>+           return v4l2_call_flash_op(flash_brightness_set, led_cdev,
> >>+                                                           c->val);
> >>+   case V4L2_CID_FLASH_INDICATOR_INTENSITY:
> >>+           /* no conversion is needed */
> >>+           return v4l2_call_flash_op(indicator_brightness_set, led_cdev,
> >>+                                                           c->val);
> >>+   case V4L2_CID_FLASH_TORCH_INTENSITY:
> >>+           if (ctrl->led_mode->val == V4L2_FLASH_LED_MODE_TORCH) {
> >>+                   torch_brightness =
> >>+                           v4l2_flash_intensity_to_led_brightness(
> >>+                                           &led_cdev->brightness_ctrl,
> >>+                                           ctrl->torch_intensity->val);
> >>+                   v4l2_call_flash_op(brightness_set, led_cdev,
> >>+                                           torch_brightness);
> >
> >I could be missing something but don't torch and indicator require similar
> >handling?
> 
> Why? Torch units need conversion whereas indicator units don't.
> Moreover they have different LED API.

I missed it was already in micro-Amps.

> >>+           }
> >>+           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 int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash)
> >>+
> >>+{
> >>+   struct led_classdev *led_cdev = v4l2_flash->led_cdev;
> >>+   struct led_flash *flash = led_cdev->flash;
> >>+   bool has_indicator = flash->indicator_brightness;
> >>+   struct v4l2_ctrl *ctrl;
> >>+   struct led_ctrl *ctrl_cfg;
> >>+   unsigned int mask;
> >>+   int ret, max, num_ctrls;
> >>+
> >>+   num_ctrls = flash->has_flash_led ? 8 : 2;
> >>+   if (flash->fault_flags)
> >>+           ++num_ctrls;
> >>+   if (has_indicator)
> >>+           ++num_ctrls;
> >>+
> >>+   v4l2_ctrl_handler_init(&v4l2_flash->hdl, num_ctrls);
> >>+
> >>+   mask = 1 << V4L2_FLASH_LED_MODE_NONE |
> >>+          1 << V4L2_FLASH_LED_MODE_TORCH;
> >>+   if (flash->has_flash_led)
> >>+           mask |= 1 << V4L2_FLASH_LED_MODE_FLASH;
> >>+
> >>+   /* Configure FLASH_LED_MODE ctrl */
> >>+   v4l2_flash->ctrl.led_mode = v4l2_ctrl_new_std_menu(
> >>+                   &v4l2_flash->hdl,
> >>+                   &v4l2_flash_ctrl_ops, V4L2_CID_FLASH_LED_MODE,
> >>+                   V4L2_FLASH_LED_MODE_TORCH, ~mask,
> >>+                   V4L2_FLASH_LED_MODE_NONE);
> >>+
> >>+   /* Configure TORCH_INTENSITY ctrl */
> >>+   ctrl_cfg = &led_cdev->brightness_ctrl;
> >>+   ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
> >>+                            V4L2_CID_FLASH_TORCH_INTENSITY,
> >>+                            ctrl_cfg->min, ctrl_cfg->max,
> >>+                            ctrl_cfg->step, ctrl_cfg->val);
> >>+   if (ctrl)
> >>+           ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
> >>+   v4l2_flash->ctrl.torch_intensity = ctrl;
> >>+
> >>+   if (flash->has_flash_led) {
> >>+           /* Configure FLASH_STROBE_SOURCE ctrl */
> >>+           mask = 1 << V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
> >>+
> >>+           if (flash->has_external_strobe) {
> >>+                   mask |= 1 << V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
> >>+                   max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
> >>+           } else {
> >>+                   max = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
> >>+           }
> >>+
> >>+           v4l2_flash->ctrl.source = v4l2_ctrl_new_std_menu(
> >>+                                   &v4l2_flash->hdl,
> >>+                                   &v4l2_flash_ctrl_ops,
> >>+                                   V4L2_CID_FLASH_STROBE_SOURCE,
> >>+                                   max,
> >>+                                   ~mask,
> >>+                                   V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
> >>+
> >>+           /* Configure FLASH_STROBE ctrl */
> >>+           ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
> >>+                                     V4L2_CID_FLASH_STROBE, 0, 1, 1, 0);
> >>+
> >>+           /* Configure FLASH_STROBE_STOP ctrl */
> >>+           ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
> >>+                                     V4L2_CID_FLASH_STROBE_STOP,
> >>+                                     0, 1, 1, 0);
> >>+
> >>+           /* Configure FLASH_STROBE_STATUS ctrl */
> >>+           ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
> >>+                                    V4L2_CID_FLASH_STROBE_STATUS,
> >>+                                    0, 1, 1, 1);
> >>+           if (ctrl)
> >>+                   ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
> >>+                                  V4L2_CTRL_FLAG_READ_ONLY;
> >>+
> >>+           /* Configure FLASH_TIMEOUT ctrl */
> >>+           ctrl_cfg = &flash->timeout;
> >>+           ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
> >>+                                    V4L2_CID_FLASH_TIMEOUT, ctrl_cfg->min,
> >>+                                    ctrl_cfg->max, ctrl_cfg->step,
> >>+                                    ctrl_cfg->val);
> >>+           if (ctrl)
> >>+                   ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
> >>+
> >>+           /* Configure FLASH_INTENSITY ctrl */
> >>+           ctrl_cfg = &flash->brightness;
> >>+           ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
> >>+                                    V4L2_CID_FLASH_INTENSITY,
> >>+                                    ctrl_cfg->min, ctrl_cfg->max,
> >>+                                    ctrl_cfg->step, ctrl_cfg->val);
> >>+           if (ctrl)
> >>+                   ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
> >>+
> >>+           if (flash->fault_flags) {
> >>+                   /* Configure FLASH_FAULT ctrl */
> >>+                   ctrl = v4l2_ctrl_new_std(&v4l2_flash->hdl,
> >>+                                            &v4l2_flash_ctrl_ops,
> >>+                                            V4L2_CID_FLASH_FAULT, 0,
> >>+                                            flash->fault_flags,
> >>+                                            0, 0);
> >>+                   if (ctrl)
> >>+                           ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
> >>+                                          V4L2_CTRL_FLAG_READ_ONLY;
> >>+           }
> >>+           if (has_indicator) {
> >
> >In theory it's possible to have an indicator without the flash. So I'd keep
> >the two independent.
> 
> OK.
> 
> >>+                   /* Configure FLASH_INDICATOR_INTENSITY ctrl */
> >>+                   ctrl_cfg = flash->indicator_brightness;
> >>+                   ctrl = v4l2_ctrl_new_std(
> >>+                                   &v4l2_flash->hdl, &v4l2_flash_ctrl_ops,
> >>+                                   V4L2_CID_FLASH_INDICATOR_INTENSITY,
> >>+                                   ctrl_cfg->min, ctrl_cfg->max,
> >>+                                   ctrl_cfg->step, ctrl_cfg->val);
> >>+                   if (ctrl)
> >>+                           ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
> >>+           }
> >>+   }
> >>+
> >>+   if (v4l2_flash->hdl.error) {
> >>+           ret = v4l2_flash->hdl.error;
> >>+           goto error_free;
> >>+   }
> >>+
> >>+   ret = v4l2_ctrl_handler_setup(&v4l2_flash->hdl);
> >>+   if (ret < 0)
> >>+           goto error_free;
> >>+
> >>+   v4l2_flash->subdev.ctrl_handler = &v4l2_flash->hdl;
> >>+
> >>+   return 0;
> >>+
> >>+error_free:
> >>+   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 *led_cdev = v4l2_flash->led_cdev;
> >>+
> >>+   mutex_lock(&led_cdev->led_lock);
> >>+   v4l2_call_flash_op(sysfs_lock, led_cdev);
> >
> >Have you thought about device power management yet?
> 
> Having in mind that the V4L2 Flash sub-device is only a wrapper
> for LED driver, shouldn't power management be left to the
> drivers?

How does the LED controller driver know it needs to power the device up in
that case?

I think an s_power() op which uses PM runtime to set the power state until
V4L2 sub-device switches to it should be enough. But I'm fine leaving it out
from this patchset.

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ai...@iki.fi     XMPP: sai...@retiisi.org.uk
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to